Skip to main content

Quick Start Guide

Get your IoT greenhouse monitoring system up and running in less than 5 minutes using Docker Compose.

Prerequisites

Before you begin, ensure you have the following installed:

Docker

Docker Engine v20.10+Download Docker

Docker Compose

Docker Compose v2.0+(Included with Docker Desktop)
Java 21 is optional - Only needed for local development without Docker. The Docker image includes the JRE.

Step 1: Clone the Repository

1

Clone from GitHub

git clone https://github.com/apptolast/InvernaderosAPI.git
cd InvernaderosAPI

Step 2: Configure Environment Variables

The system requires secure passwords for database and MQTT connections.
1

Copy the example environment file

cp .env.example .env
2

Generate secure passwords

Use OpenSSL to generate strong passwords:
# Generate 5 random passwords
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
3

Edit the .env file

Open .env in your text editor and replace placeholders:
.env
# TimescaleDB (Time-series Database)
TIMESCALE_DB_NAME=greenhouse_timeseries
TIMESCALE_USER=admin
TIMESCALE_PASSWORD=<paste_generated_password_1>

# PostgreSQL Metadata Database
METADATA_DB_NAME=greenhouse_metadata
METADATA_USER=admin
METADATA_PASSWORD=<paste_generated_password_2>

# Redis Cache
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=<paste_generated_password_3>

# MQTT Broker (EMQX)
MQTT_BROKER_URL=tcp://emqx:1883
MQTT_USERNAME=mqtt_user
MQTT_PASSWORD=<paste_generated_password_4>
MQTT_CLIENT_ID_PREFIX=api_local_001

# EMQX Dashboard
EMQX_DASHBOARD_USERNAME=admin
EMQX_DASHBOARD_PASSWORD=<paste_generated_password_5>

# Spring Boot
SPRING_PROFILES_ACTIVE=local
JAVA_OPTS=-Xms256m -Xmx512m
Never use default passwords in production! Generate unique, strong passwords for each service and rotate them regularly.

Step 3: Configure Application Settings

1

Copy application configuration

cp application-local.yaml.example application-local.yaml
This file configures the Spring Boot application. The default settings are optimized for local development.
The application-local.yaml file is volume-mounted into the Docker container at /app/config/application.yaml. You can modify settings without rebuilding the image.

Step 4: Start All Services

1

Start with Docker Compose

docker-compose up -d
This command will:
  • Pull required Docker images (TimescaleDB, PostgreSQL, Redis, EMQX)
  • Build the Spring Boot API image
  • Start all 5 services in detached mode
  • Create Docker networks and volumes
2

Monitor startup logs

docker-compose logs -f api
Wait for this message:
Started InvernaderosApplication in X.XXX seconds
Press Ctrl+C to stop following logs.
3

Verify all services are running

docker-compose ps
Expected output:
NAME                         STATUS
invernaderos-api             Up (healthy)
invernaderos-emqx            Up (healthy)
invernaderos-postgres        Up (healthy)
invernaderos-redis           Up (healthy)
invernaderos-timescaledb     Up (healthy)

Step 5: Verify API is Running

1

Health check endpoint

curl http://localhost:8080/actuator/health
Expected response:
{
  "status": "UP"
}
2

Check cache status

curl http://localhost:8080/api/v1/greenhouse/cache/info
Expected response:
{
  "totalMessages": 0,
  "ttlSeconds": 86400,
  "maxCapacity": 1000,
  "utilizationPercentage": 0.0,
  "cacheType": "Redis Sorted Set"
}

Step 6: Explore the API

Open your browser and access the interactive API documentation:

Swagger UI

Interactive API explorer with try-it-out functionality

OpenAPI Spec

OpenAPI 3.0 JSON specification

EMQX Dashboard

MQTT broker management (login with EMQX credentials)

Actuator

Health, metrics, and monitoring endpoints

Step 7: Test with Sample Data

Now let’s send a test MQTT message to verify the system is working.
The API automatically processes MQTT messages, caches them in Redis, saves to TimescaleDB, and broadcasts via WebSocket to connected clients.

Docker Compose Services

The docker-compose.yaml defines 5 services:
ServiceContainer NamePortsPurpose
apiinvernaderos-api8080Spring Boot API
timescaledbinvernaderos-timescaledb5432Time-series database
postgresql-metadatainvernaderos-postgres-metadata5433→5432Metadata database
redisinvernaderos-redis6379Cache
emqxinvernaderos-emqx1883, 8083, 18083MQTT broker
version: '3.8'

services:
  # TimescaleDB - Time-series Database
  timescaledb:
    image: timescale/timescaledb:latest-pg16
    container_name: invernaderos-timescaledb
    environment:
      POSTGRES_DB: ${TIMESCALE_DB_NAME:-greenhouse_timeseries}
      POSTGRES_USER: ${TIMESCALE_USER:-admin}
      POSTGRES_PASSWORD: ${TIMESCALE_PASSWORD}
    ports:
      - "5432:5432"
    volumes:
      - timescaledb_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${TIMESCALE_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
  
  # PostgreSQL - Metadata Database
  postgresql-metadata:
    image: postgres:16-alpine
    container_name: invernaderos-postgres-metadata
    environment:
      POSTGRES_DB: ${METADATA_DB_NAME:-greenhouse_metadata}
      POSTGRES_USER: ${METADATA_USER:-admin}
      POSTGRES_PASSWORD: ${METADATA_PASSWORD}
    ports:
      - "5433:5432"
    volumes:
      - postgres_metadata_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${METADATA_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
  
  # Redis - Cache
  redis:
    image: redis:7-alpine
    container_name: invernaderos-redis
    command: redis-server --requirepass ${REDIS_PASSWORD}
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
  
  # EMQX - MQTT Broker
  emqx:
    image: emqx/emqx:latest
    container_name: invernaderos-emqx
    environment:
      EMQX_DASHBOARD__DEFAULT_USERNAME: ${EMQX_DASHBOARD_USERNAME:-admin}
      EMQX_DASHBOARD__DEFAULT_PASSWORD: ${EMQX_DASHBOARD_PASSWORD}
    ports:
      - "1883:1883"      # MQTT
      - "8083:8083"      # MQTT/WebSocket
      - "18083:18083"    # Dashboard
    healthcheck:
      test: ["CMD", "/opt/emqx/bin/emqx", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
  
  # Invernaderos API - Spring Boot Application
  api:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: invernaderos-api
    environment:
      SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-local}
      TIMESCALE_PASSWORD: ${TIMESCALE_PASSWORD}
      METADATA_PASSWORD: ${METADATA_PASSWORD}
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      MQTT_BROKER_URL: ${MQTT_BROKER_URL:-tcp://emqx:1883}
      MQTT_USERNAME: ${MQTT_USERNAME}
      MQTT_PASSWORD: ${MQTT_PASSWORD}
      MQTT_CLIENT_ID_PREFIX: ${MQTT_CLIENT_ID_PREFIX:-api_local_001}
    ports:
      - "8080:8080"
    volumes:
      - ./application-local.yaml:/app/config/application.yaml:ro
    depends_on:
      timescaledb:
        condition: service_healthy
      postgresql-metadata:
        condition: service_healthy
      redis:
        condition: service_healthy
      emqx:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 60s

volumes:
  timescaledb_data:
  postgres_metadata_data:
  redis_data:

Common Commands

# Follow API logs
docker-compose logs -f api

# View all logs
docker-compose logs

# Last 100 lines
docker-compose logs --tail=100 api

Troubleshooting

Check if ports are already in use:
lsof -i :8080  # API
lsof -i :5432  # TimescaleDB
lsof -i :5433  # PostgreSQL
lsof -i :6379  # Redis
lsof -i :1883  # MQTT
Stop conflicting services or modify ports in docker-compose.yaml
Check environment variables:
docker-compose config
Verify passwords match in .env and application-local.yamlReset databases (⚠️ deletes all data):
docker-compose down -v
docker-compose up -d
Check MQTT credentials in .env:
cat .env | grep MQTT
Test MQTT connection:
mosquitto_pub -h localhost -p 1883 \
  -u mqtt_user -P <password> \
  -t "test" -m "hello"
View EMQX logs:
docker-compose logs emqx
View API logs:
docker-compose logs api --tail=100
Check health status:
curl http://localhost:8080/actuator/health
Verify all services are healthy:
docker-compose ps

Next Steps

Architecture

Understand the system design and components

API Reference

Explore all REST endpoints

WebSocket

Connect to real-time data stream

Congratulations! Your Invernaderos API is now running. You can start sending sensor data via MQTT and querying it via REST or WebSocket.

Build docs developers (and LLMs) love