diff --git a/.env.example b/.env.example index 59fa6b2..15b3ba5 100644 --- a/.env.example +++ b/.env.example @@ -73,3 +73,15 @@ VITE_PORT=5175 WWWGROUP=1000 WWWUSER=1000 + +# MQTT / EMQX +MQTT_BROKER_ADDR=tcp://emqx:1883 +MQTT_GATEWAY_CLIENT_ID=star-cloud-gateway +MQTT_REDIS_ADDR=redis:6379 +MQTT_REDIS_PASSWORD=${REDIS_PASSWORD} +MQTT_INCOMING_QUEUE=mqtt_incoming_jobs +MQTT_OUTGOING_QUEUE=mqtt_outgoing_commands + +# EMQX Ports (for local dev) +MQTT_PORT=1883 +EMQX_DASHBOARD_PORT=18083 diff --git a/.gitea/workflows/deploy-demo.yaml b/.gitea/workflows/deploy-demo.yaml index 6a9a2bc..7caccc4 100644 --- a/.gitea/workflows/deploy-demo.yaml +++ b/.gitea/workflows/deploy-demo.yaml @@ -23,9 +23,9 @@ jobs: - name: Step 2 - Deploy Code run: | - # Runner 容器模式下,volume mount 無法正確對應宿主機路徑 - # 使用 docker cp 直接將程式碼注入容器(透過 Docker socket) docker cp . star-cloud-laravel:/var/www/html/ + docker cp . star-cloud-queue:/var/www/html/ + docker cp . star-cloud-mqtt-worker:/var/www/html/ docker exec star-cloud-laravel sh -c " chown -R 1000:1000 /var/www/html && mkdir -p /.npm && chown -R 1000:1000 /.npm && diff --git a/compose.yaml b/compose.yaml index ea9e6ad..01bbcbc 100644 --- a/compose.yaml +++ b/compose.yaml @@ -15,6 +15,7 @@ services: - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' environment: WWWUSER: '${WWWUSER}' + SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80" LARAVEL_SAIL: 1 XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' @@ -45,6 +46,24 @@ services: - mysql - redis restart: always + laravel.mqtt: + image: 'sail-8.5/app' + container_name: star-cloud-mqtt-worker + hostname: star-cloud-mqtt-worker + command: php artisan mqtt:listen + environment: + WWWUSER: '${WWWUSER}' + LARAVEL_SAIL: 1 + TZ: 'Asia/Taipei' + volumes: + - '.:/var/www/html' + networks: + - sail + depends_on: + - mysql + - redis + - emqx + restart: always mysql: image: 'mysql/mysql-server:8.0' @@ -119,12 +138,13 @@ services: container_name: star-cloud-mqtt-gateway hostname: mqtt-gateway environment: - MQTT_BROKER_ADDR: 'tcp://emqx:1883' - MQTT_GATEWAY_CLIENT_ID: 'star-cloud-gateway' - MQTT_REDIS_ADDR: 'star-cloud-redis:6379' + MQTT_BROKER_ADDR: '${MQTT_BROKER_ADDR:-tcp://emqx:1883}' + MQTT_GATEWAY_CLIENT_ID: '${MQTT_GATEWAY_CLIENT_ID:-star-cloud-gateway}' + MQTT_REDIS_ADDR: '${MQTT_REDIS_ADDR:-redis:6379}' MQTT_REDIS_PASSWORD: '${REDIS_PASSWORD:-}' - MQTT_INCOMING_QUEUE: 'mqtt_incoming_jobs' - MQTT_OUTGOING_QUEUE: 'mqtt_outgoing_commands' + MQTT_REDIS_PREFIX: '${MQTT_REDIS_PREFIX:-starcloud_database_}' + MQTT_INCOMING_QUEUE: '${MQTT_INCOMING_QUEUE:-mqtt_incoming_jobs}' + MQTT_OUTGOING_QUEUE: '${MQTT_OUTGOING_QUEUE:-mqtt_outgoing_commands}' TZ: 'Asia/Taipei' networks: - sail diff --git a/mqtt-gateway/Dockerfile b/mqtt-gateway/Dockerfile index 3806ae8..791c13b 100644 --- a/mqtt-gateway/Dockerfile +++ b/mqtt-gateway/Dockerfile @@ -14,6 +14,9 @@ RUN CGO_ENABLED=0 go build -o gateway . # Stage 2: Run FROM alpine:3.20 +# 安裝 tzdata 以支援時區設定 +RUN apk add --no-cache tzdata + WORKDIR /root/ COPY --from=builder /app/gateway . diff --git a/mqtt-gateway/config/config.go b/mqtt-gateway/config/config.go index 910664b..b386c89 100644 --- a/mqtt-gateway/config/config.go +++ b/mqtt-gateway/config/config.go @@ -11,6 +11,7 @@ type Config struct { RedisPassword string IncomingQueueKey string OutgoingQueueKey string + RedisPrefix string } func LoadConfig() *Config { @@ -21,6 +22,7 @@ func LoadConfig() *Config { RedisPassword: getEnv("MQTT_REDIS_PASSWORD", ""), IncomingQueueKey: getEnv("MQTT_INCOMING_QUEUE", "mqtt_incoming_jobs"), OutgoingQueueKey: getEnv("MQTT_OUTGOING_QUEUE", "mqtt_outgoing_commands"), + RedisPrefix: getEnv("MQTT_REDIS_PREFIX", "starcloud_database_"), } } diff --git a/mqtt-gateway/main.go b/mqtt-gateway/main.go index b43a5ce..ecc761e 100644 --- a/mqtt-gateway/main.go +++ b/mqtt-gateway/main.go @@ -39,7 +39,7 @@ func main() { } // 加入 Laravel 前綴,確保雙方桶子同一個 - prefixedIncomingKey := "starcloud_database_" + cfg.IncomingQueueKey + prefixedIncomingKey := cfg.RedisPrefix + cfg.IncomingQueueKey pusher := bridge.NewRedisPusher(rdb, prefixedIncomingKey) mqttHandler := handler.NewMqttHandler(pusher) @@ -76,7 +76,8 @@ func main() { } // 3. 啟動 Redis Consumer (下行指令) - consumer := bridge.NewRedisConsumer(rdb, client, cfg.OutgoingQueueKey) + prefixedOutgoingKey := cfg.RedisPrefix + cfg.OutgoingQueueKey + consumer := bridge.NewRedisConsumer(rdb, client, prefixedOutgoingKey) ctx, cancel := context.WithCancel(context.Background()) go consumer.Start(ctx) diff --git a/simulate-heartbeat.sh b/simulate-heartbeat.sh index a84d36b..3f1dff7 100755 --- a/simulate-heartbeat.sh +++ b/simulate-heartbeat.sh @@ -7,8 +7,8 @@ # 依賴:Docker (使用 eclipse-mosquitto 鏡像進行發送) # ================================================================= -SERIAL_NO="SN00001" -API_TOKEN="8QwOrmKX6sLmR5T1sChfvGjfc8eS4qaclOFd4ocItmeryii7SFqcC5uMpnzg" +SERIAL_NO="M000001" +API_TOKEN="VfFFb0DIUqtLTPF4jyCsB2h5fWsMcVxCPboNHpKc3XzRComLEK07xFYRUzBJ" TOPIC="machine/${SERIAL_NO}/heartbeat" NETWORK="star-cloud_sail" BROKER_HOST="emqx" diff --git a/vite.config.js b/vite.config.js index 89f26f5..3899c47 100644 --- a/vite.config.js +++ b/vite.config.js @@ -2,6 +2,14 @@ import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; export default defineConfig({ + server: { + hmr: { + host: 'localhost', + }, + host: '0.0.0.0', + port: 5175, + strictPort: true, + }, plugins: [ laravel({ input: [