System Architecture¶
This document provides a comprehensive overview of GreenCop's architecture, explaining how all components work together to create a scalable IoT monitoring system.
Architecture Overview¶
GreenCop follows an event-driven, cloud-native architecture built on Google Cloud Platform. The system is divided into four main layers:
- Edge Layer: ESP32 sensor nodes
- Gateway Layer: Local HTTP server for data collection
- Cloud Layer: GCP services for processing and storage
- Application Layer: Backend API and frontend dashboard
graph TB
subgraph Edge["Edge Layer"]
ESP32_1[ESP32 Sensor 1]
ESP32_2[ESP32 Sensor 2]
ESP32_N[ESP32 Sensor N]
end
subgraph Gateway["Gateway Layer"]
GW[Gateway Service<br/>HTTP Server<br/>Port 8000]
end
subgraph Cloud["Google Cloud Platform"]
subgraph EventStreaming["Event Streaming"]
PS_DATA[Pub/Sub Topic: data]
PS_ALERT[Pub/Sub Topic: alerts]
end
subgraph Serverless["Serverless Processing"]
CF_INGEST[Cloud Function<br/>Data Ingestion]
CF_ALERT[Cloud Function<br/>Alert Detection]
CF_NOTIFY[Cloud Function<br/>Alert Subscriber]
end
subgraph Storage["Data Storage"]
BQ[BigQuery<br/>sensor_data.readings]
SQL[(Cloud SQL<br/>PostgreSQL)]
end
subgraph Compute["Application Services"]
API[Cloud Run<br/>FastAPI Backend]
end
end
subgraph Client["Client Layer"]
WEB[React Frontend<br/>Web Dashboard]
end
ESP32_1 -->|HTTP POST| GW
ESP32_2 -->|HTTP POST| GW
ESP32_N -->|HTTP POST| GW
GW -->|Publish| PS_DATA
PS_DATA -->|Trigger| CF_INGEST
PS_DATA -->|Trigger| CF_ALERT
CF_INGEST -->|Insert| BQ
CF_ALERT -->|Publish| PS_ALERT
PS_ALERT -->|Trigger| CF_NOTIFY
CF_NOTIFY -->|Store| SQL
API <-->|Query/Store| SQL
API <-->|Query| BQ
WEB <-->|REST API<br/>JWT Auth| API
Component Details¶
Updated System Architecture with Go Gateway¶
graph TB
subgraph Edge["Edge Layer - IoT Sensors"]
ESP32_1[ESP32 Sensor 1<br/>MicroPython]
ESP32_2[ESP32 Sensor 2<br/>MicroPython]
ESP32_N[ESP32 Sensor N<br/>MicroPython]
end
subgraph LocalGateway["Local Network - Go Gateway"]
GW[Go Gateway Service<br/>Port 8080]
MDNS[mDNS Service<br/>greencop-gateway.local]
end
subgraph Cloud["Google Cloud Platform"]
subgraph EventStreaming["Event Streaming"]
PS_DATA[Pub/Sub Topic: data]
PS_ALERT[Pub/Sub Topic: alerts]
end
subgraph Serverless["Serverless Processing"]
CF_INGEST[Cloud Function<br/>Data Ingestion<br/>Python]
CF_ALERT[Cloud Function<br/>Alert Detection<br/>Python]
CF_NOTIFY[Cloud Function<br/>Alert Subscriber<br/>Python]
end
subgraph Storage["Data Storage"]
BQ[BigQuery<br/>sensor_data.readings]
SQL[(Cloud SQL<br/>PostgreSQL)]
end
subgraph Compute["Application Services"]
API[Cloud Run<br/>FastAPI Backend<br/>Python]
end
end
subgraph Client["Client Layer"]
WEB[React Frontend<br/>Web Dashboard<br/>TypeScript]
end
GW -->|Broadcasts| MDNS
ESP32_1 -.->|mDNS Discover| MDNS
ESP32_2 -.->|mDNS Discover| MDNS
ESP32_N -.->|mDNS Discover| MDNS
ESP32_1 -->|HTTP POST<br/>Auto-Register| GW
ESP32_2 -->|HTTP POST<br/>Auto-Register| GW
ESP32_N -->|HTTP POST<br/>Auto-Register| GW
GW -->|Publish Messages| PS_DATA
PS_DATA -->|Trigger| CF_INGEST
PS_DATA -->|Trigger| CF_ALERT
CF_INGEST -->|Insert Rows| BQ
CF_ALERT -->|Publish| PS_ALERT
PS_ALERT -->|Trigger| CF_NOTIFY
CF_NOTIFY -->|Store Alerts| SQL
API <-->|Query/Store| SQL
API <-->|Query Analytics| BQ
WEB <-->|REST API<br/>JWT Auth| API
style GW fill:#90EE90
style MDNS fill:#90EE90
style ESP32_1 fill:#FFE4B5
style ESP32_2 fill:#FFE4B5
style ESP32_N fill:#FFE4B5
Key Components¶
Go Gateway (Local): - Written in Go for performance - HTTP server on port 8080 - mDNS broadcasting for auto-discovery - Manages sensor registration - Routes messages to GCP Pub/Sub
Auto-Registration via mDNS:
- Gateway broadcasts greencop-gateway.local
- ESP32 sensors discover gateway automatically
- No hardcoded IP addresses needed
- Zero-configuration deployment
Distributed System Architecture: - Edge: ESP32 sensors (autonomous, auto-registering) - Coordination: Go gateway (local aggregator) - Cloud: GCP services (processing & storage)
Edge Layer: ESP32 Sensors¶
Technology: ESP32 microcontroller with MicroPython
Responsibilities:
- Read temperature/humidity from sensors
- Connect to WiFi network
- Auto-register with gateway
- Publish readings via HTTP POST
- Provide visual status via LED indicators
- Send heartbeat for health monitoring
Key Features:
- Autonomous Operation: Sensors operate independently
- Auto-Registration: Unique hardware ID for identification
- LED Status Indicators:
- GPIO 5 (Green): Data publishing in progress
- GPIO 4 (Red): Error conditions
- Configurable Interval: Adjustable reading frequency
Code Location: /services/sensors/hardware/main.py
Data Format:
{
"node_id": "esp32_abc123",
"temperature": 25.3,
"humidity": 45.2,
"timestamp": "2025-01-15T10:30:00Z"
}
Gateway Layer¶
Technology: HTTP server (local or cloud-hosted)
Responsibilities:
- Receive sensor data via HTTP POST
- Validate incoming messages
- Publish to Google Cloud Pub/Sub
- Handle sensor registration
- Process heartbeat requests
Endpoints:
POST /api/v1/message: Receive sensor dataPOST /api/v1/register: Register new sensorPOST /api/v1/heartbeat: Health check
Code Location: /services/gateway/ (if using separate gateway)
Discovery: Available via mDNS at greencop-gateway.local
Cloud Layer¶
1. Event Streaming: Google Cloud Pub/Sub¶
Purpose: Decouple data producers from consumers
Topics:
- data: Raw sensor readings from gateway
- alerts: Alert events when thresholds exceeded
Benefits:
- Scalable message delivery
- At-least-once delivery guarantee
- Multiple subscribers per topic
- Message buffering and retry
Configuration: /infra/terraform/modules/pubsub/
2. Serverless Processing: Cloud Functions¶
Data Ingestion Function¶
Trigger: Pub/Sub topic data
Purpose: Stream sensor data to BigQuery
Runtime: Python 3.12
Process:
- Receive message from Pub/Sub
- Parse and validate sensor data
- Insert into BigQuery table
- Acknowledge message
Code: /services/pubsub_bq_bridge/main.py
Environment Variables:
PROJECT_ID: GCP projectDATASET_ID: BigQuery dataset (default:sensor_data)TABLE_ID: BigQuery table (default:readings)
Alert Detection Function¶
Trigger: Pub/Sub topic data
Purpose: Detect threshold violations
Runtime: Python 3.12
Process:
- Receive sensor reading
- Check against thresholds:
- Temperature > 50°C
- Humidity > 40%
- If exceeded, publish to
alertstopic
Code: /services/alerts/main.py
Thresholds (configurable via environment):
Alert Subscriber Function¶
Trigger: Pub/Sub topic alerts
Purpose: Store alerts in database
Runtime: Python 3.12
Process:
- Receive alert from Pub/Sub
- Determine alert type (temperature/humidity)
- Insert into PostgreSQL alerts table
- Mark as unacknowledged
Code: /services/alert_subscriber/main.py
3. Data Storage¶
BigQuery: Time-Series Data Warehouse¶
Dataset: sensor_data
Table: readings
Schema:
| Column | Type | Description |
|---|---|---|
| node_id | STRING | Sensor identifier |
| message_id | STRING | Unique message ID |
| timestamp | TIMESTAMP | Reading time (UTC) |
| temperature | FLOAT64 | Temperature in Celsius |
| humidity | FLOAT64 | Relative humidity (%) |
Optimization:
- Partitioned by
timestamp(daily partitions) - Clustered by
node_idandmessage_id - Optimized for time-range queries
Use Cases:
- Historical data analysis
- Trend visualization
- Statistics computation
- Long-term storage
Cloud SQL (PostgreSQL): Metadata Storage¶
Database: greencop
Tables:
- customers: User accounts
- server_rooms: Physical/logical rooms
- sensors: Sensor metadata
- alerts: Alert history
- alert_thresholds: Per-customer thresholds
Schema Details:
-- customers table
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
username VARCHAR(80) UNIQUE NOT NULL,
password_hash VARCHAR(120) NOT NULL,
email VARCHAR(120) UNIQUE NOT NULL
);
-- server_rooms table
CREATE TABLE server_rooms (
id SERIAL PRIMARY KEY,
name VARCHAR(120) NOT NULL,
customer_id INTEGER REFERENCES customers(id)
);
-- sensors table
CREATE TABLE sensors (
id SERIAL PRIMARY KEY,
name VARCHAR(80) NOT NULL,
type VARCHAR(50) NOT NULL,
room_id INTEGER REFERENCES server_rooms(id)
);
-- alerts table
CREATE TABLE alerts (
id SERIAL PRIMARY KEY,
sensor_id VARCHAR(50) NOT NULL,
alert_type VARCHAR(50) NOT NULL,
message TEXT,
timestamp TIMESTAMP DEFAULT NOW(),
acknowledged BOOLEAN DEFAULT FALSE
);
-- alert_thresholds table
CREATE TABLE alert_thresholds (
id SERIAL PRIMARY KEY,
customer_id INTEGER REFERENCES customers(id),
max_temperature FLOAT DEFAULT 50.0,
max_humidity FLOAT DEFAULT 50.0
);
Migrations: Managed with Alembic (/services/customers/alembic/)
4. Application Services: Cloud Run¶
Service: FastAPI Backend Container: Docker image on Google Container Registry Scaling: Automatic based on request load
Responsibilities:
- REST API for frontend
- User authentication (JWT)
- CRUD operations for rooms/sensors
- Query BigQuery for sensor data
- Manage alerts and thresholds
Code: /services/customers/main.py
Configuration: /infra/terraform/modules/cloud_run/
Application Layer¶
Backend: FastAPI¶
Framework: FastAPI with Uvicorn Language: Python 3.12 ORM: SQLAlchemy 2.0+
Architecture:
services/customers/
├── main.py # Application entry point
├── api/
│ ├── routes/ # Endpoint definitions
│ │ ├── customer.py
│ │ ├── server_room.py
│ │ ├── sensor.py
│ │ ├── data.py
│ │ └── alert.py
│ ├── schemas/ # Pydantic models
│ └── utils/ # Auth, hashing utilities
├── database/
│ ├── session.py # Database connection
│ └── models/ # SQLAlchemy models
└── alembic/ # Database migrations
Key Features:
- Automatic API documentation (Swagger/OpenAPI)
- Request/response validation (Pydantic)
- JWT-based authentication
- CORS middleware for frontend
- BigQuery integration for analytics
Frontend: React Dashboard¶
Framework: React 19.2.0 with TypeScript Build Tool: Vite Styling: Tailwind CSS Charts: Recharts
Architecture:
web/frontend/src/
├── main.tsx # Entry point
├── App.tsx # Router configuration
├── pages/ # Page components
│ ├── DashboardPage.tsx
│ ├── RoomsPage.tsx
│ ├── SensorsPage.tsx
│ ├── SensorDetailPage.tsx
│ ├── AlertsPage.tsx
│ ├── SettingsPage.tsx
│ └── AssistantPage.tsx
├── components/
│ ├── layout/ # Layout components
│ └── ui/ # Reusable UI components
├── api/
│ ├── client.ts # Axios instance
│ └── services/ # API service methods
├── hooks/ # Custom React hooks
├── context/ # React Context (Auth)
└── types/ # TypeScript types
Key Features:
- Protected routes with auth check
- Real-time data polling
- Interactive charts and graphs
- Responsive design
- JWT token management
Data Flow Scenarios¶
Scenario 1: Sensor Reading Flow¶
sequenceDiagram
participant Sensor as ESP32 Sensor
participant Gateway
participant PubSub as Pub/Sub (data)
participant Ingest as Ingestion Function
participant Alert as Alert Function
participant BQ as BigQuery
participant AlertTopic as Pub/Sub (alerts)
Sensor->>Gateway: POST /api/v1/message<br/>{temp: 55, humidity: 35}
Gateway->>PubSub: Publish message
PubSub->>Ingest: Trigger function
PubSub->>Alert: Trigger function
Ingest->>BQ: Insert reading
Alert->>Alert: Check thresholds<br/>temp > 50°C ✓
Alert->>AlertTopic: Publish alert
Gateway-->>Sensor: 200 OK
Scenario 2: User Views Dashboard¶
sequenceDiagram
participant User
participant Frontend as React App
participant API as FastAPI
participant SQL as PostgreSQL
participant BQ as BigQuery
User->>Frontend: Open dashboard
Frontend->>API: GET /api/v1/server_rooms/list_rooms/{customer_id}
API->>SQL: SELECT * FROM server_rooms
SQL-->>API: Room data
API-->>Frontend: JSON response
Frontend->>API: GET /api/v1/sensors/list_sensors/{room_id}
API->>SQL: SELECT * FROM sensors
SQL-->>API: Sensor metadata
API-->>Frontend: JSON response
Frontend->>API: POST /api/v1/data/multi-sensor
API->>BQ: SELECT latest readings
BQ-->>API: Sensor data
API-->>Frontend: JSON response
Frontend-->>User: Display dashboard
Scenario 3: Alert Triggered¶
sequenceDiagram
participant Sensor as ESP32
participant Gateway
participant PubSub as Pub/Sub
participant Alert as Alert Function
participant AlertPubSub as Alert Topic
participant Subscriber as Alert Subscriber
participant DB as PostgreSQL
participant User
Sensor->>Gateway: High temp reading (60°C)
Gateway->>PubSub: Publish to data topic
PubSub->>Alert: Trigger alert detection
Alert->>Alert: Check: 60 > 50? YES
Alert->>AlertPubSub: Publish alert event
AlertPubSub->>Subscriber: Trigger subscriber
Subscriber->>DB: INSERT INTO alerts
Note over User: Later...
User->>User: Opens alerts page
User->>User: Sees unacknowledged alert
User->>User: Clicks "Acknowledge"
User->>DB: UPDATE alerts SET acknowledged=true
Scaling Considerations¶
Horizontal Scaling¶
ESP32 Sensors: Add unlimited sensors; each auto-registers
Gateway: Stateless; can run multiple instances behind load balancer
Cloud Functions: Auto-scale based on Pub/Sub message volume
Cloud Run: Auto-scales API based on request count
BigQuery: Automatically handles increasing data volume
Vertical Scaling¶
PostgreSQL: Upgrade Cloud SQL instance for more connections/memory
Frontend: CDN distribution for global users
Cost Optimization¶
- BigQuery partitioning reduces query costs
- Cloud Functions only charged when executing
- Cloud Run scales to zero when not in use
- Pub/Sub message retention configurable
Security Architecture¶
Authentication Flow¶
sequenceDiagram
participant User
participant Frontend
participant API
participant DB
User->>Frontend: Enter credentials
Frontend->>API: POST /api/v1/customers/login
API->>DB: SELECT user WHERE email=?
DB-->>API: User record
API->>API: Verify password (bcrypt)
API->>API: Generate JWT token (HS256)
API-->>Frontend: {access_token: "eyJ..."}
Frontend->>Frontend: Store in localStorage
Note over User,DB: Subsequent requests
Frontend->>API: GET /api/v1/sensors<br/>Authorization: Bearer eyJ...
API->>API: Verify JWT signature
API->>API: Check expiration
API->>DB: Query data
DB-->>API: Results
API-->>Frontend: JSON response
Security Measures¶
- JWT Tokens: 30-minute expiration
- Password Hashing: bcrypt with salt
- CORS: Restricted origins
- HTTPS: All cloud communication encrypted
- IAM: Google Cloud service accounts with minimal permissions
- API Keys: Not exposed in frontend code
Monitoring & Observability¶
Metrics¶
- Cloud Functions: Execution count, errors, duration
- Cloud Run: Request count, latency, instance count
- BigQuery: Query costs, slot usage
- Pub/Sub: Message count, age, delivery rate
Logging¶
- Application Logs: Cloud Logging
- Function Logs: Cloud Functions logs
- API Logs: FastAPI access logs
Alerting¶
- GCP Alerts: Configure via Cloud Monitoring
- Application Alerts: Temperature/humidity thresholds
Infrastructure as Code¶
All infrastructure defined in Terraform:
infra/terraform/
├── main.tf # Main orchestration
├── variables.tf # Input variables
├── outputs.tf # Output values
└── modules/
├── cloud_run/ # API service
├── cloud_sql/ # PostgreSQL
├── pubsub/ # Event topics
├── cloud_function/ # Serverless functions
└── bigquery/ # Data warehouse
Benefits:
- Reproducible infrastructure
- Version-controlled changes
- Environment parity (dev/prod)
- Easy disaster recovery
Technology Choices¶
Why ESP32?¶
- WiFi built-in
- Low cost ($5-10)
- MicroPython support
- GPIO for LED indicators
- Large community
Why Google Cloud?¶
- Serverless options (Functions, Run)
- BigQuery for analytics
- Pub/Sub for event streaming
- Integrated IAM
- Free tier for development
Why FastAPI?¶
- High performance (async)
- Automatic API docs
- Type validation
- Modern Python features
- Easy to learn
Why React?¶
- Component-based
- Large ecosystem
- TypeScript support
- Fast development
- Production-ready
Future Architecture Enhancements¶
Planned Features¶
- ML Anomaly Detection: Identify unusual patterns
- Email/SMS Notifications: Alert delivery
- AI Assistant: Natural language queries
- Gateway Redundancy: High availability
- Dead Letter Queue: Handle failed messages
Potential Optimizations¶
- Redis caching layer
- GraphQL instead of REST
- WebSocket for real-time updates
- Edge computing for local processing
- Multi-region deployment
Next Steps¶
Gateway Service Architecture¶
For detailed information about the Go gateway service and mDNS auto-discovery, see:
Distributed Architecture & Auto-Discovery
Quick Summary:
- Language: Go
- Purpose: Bridge between ESP32 sensors and cloud
- Key Feature: mDNS broadcasting at greencop-gateway.local
- Endpoints: /api/v1/register, /api/v1/message, /api/v1/heartbeat
- Zero-Config: Sensors auto-discover gateway via mDNS