[FEAT] 整合 MQTT 資料流自動化與環境埠號修復

1. 整合 MQTT Gateway 並支援動態 Redis Key 前綴隔離,解決多環境衝突。
2. 修正本地開發環境與 Demo 環境的埠號映射 (80/8080) 與 Vite HMR (5175) 設定。
3. 更新 CI/CD 部署流程,新增自動同步程式碼至 MQTT Worker 與 Queue 容器。
4. 擴充 .env.example 以提供完整的 MQTT/EMQX 相關變數範本。
5. 更新模擬腳本以符合現有測試資料。
This commit is contained in:
sky121113 2026-04-17 13:22:46 +08:00
parent e3ad7dd44f
commit bf43a33df3
8 changed files with 57 additions and 11 deletions

View File

@ -73,3 +73,15 @@ VITE_PORT=5175
WWWGROUP=1000 WWWGROUP=1000
WWWUSER=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

View File

@ -23,9 +23,9 @@ jobs:
- name: Step 2 - Deploy Code - name: Step 2 - Deploy Code
run: | run: |
# Runner 容器模式下volume mount 無法正確對應宿主機路徑
# 使用 docker cp 直接將程式碼注入容器(透過 Docker socket
docker cp . star-cloud-laravel:/var/www/html/ 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 " docker exec star-cloud-laravel sh -c "
chown -R 1000:1000 /var/www/html && chown -R 1000:1000 /var/www/html &&
mkdir -p /.npm && chown -R 1000:1000 /.npm && mkdir -p /.npm && chown -R 1000:1000 /.npm &&

View File

@ -15,6 +15,7 @@ services:
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}' - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment: environment:
WWWUSER: '${WWWUSER}' 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 LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
@ -45,6 +46,24 @@ services:
- mysql - mysql
- redis - redis
restart: always 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: mysql:
image: 'mysql/mysql-server:8.0' image: 'mysql/mysql-server:8.0'
@ -119,12 +138,13 @@ services:
container_name: star-cloud-mqtt-gateway container_name: star-cloud-mqtt-gateway
hostname: mqtt-gateway hostname: mqtt-gateway
environment: environment:
MQTT_BROKER_ADDR: 'tcp://emqx:1883' MQTT_BROKER_ADDR: '${MQTT_BROKER_ADDR:-tcp://emqx:1883}'
MQTT_GATEWAY_CLIENT_ID: 'star-cloud-gateway' MQTT_GATEWAY_CLIENT_ID: '${MQTT_GATEWAY_CLIENT_ID:-star-cloud-gateway}'
MQTT_REDIS_ADDR: 'star-cloud-redis:6379' MQTT_REDIS_ADDR: '${MQTT_REDIS_ADDR:-redis:6379}'
MQTT_REDIS_PASSWORD: '${REDIS_PASSWORD:-}' MQTT_REDIS_PASSWORD: '${REDIS_PASSWORD:-}'
MQTT_INCOMING_QUEUE: 'mqtt_incoming_jobs' MQTT_REDIS_PREFIX: '${MQTT_REDIS_PREFIX:-starcloud_database_}'
MQTT_OUTGOING_QUEUE: 'mqtt_outgoing_commands' MQTT_INCOMING_QUEUE: '${MQTT_INCOMING_QUEUE:-mqtt_incoming_jobs}'
MQTT_OUTGOING_QUEUE: '${MQTT_OUTGOING_QUEUE:-mqtt_outgoing_commands}'
TZ: 'Asia/Taipei' TZ: 'Asia/Taipei'
networks: networks:
- sail - sail

View File

@ -14,6 +14,9 @@ RUN CGO_ENABLED=0 go build -o gateway .
# Stage 2: Run # Stage 2: Run
FROM alpine:3.20 FROM alpine:3.20
# 安裝 tzdata 以支援時區設定
RUN apk add --no-cache tzdata
WORKDIR /root/ WORKDIR /root/
COPY --from=builder /app/gateway . COPY --from=builder /app/gateway .

View File

@ -11,6 +11,7 @@ type Config struct {
RedisPassword string RedisPassword string
IncomingQueueKey string IncomingQueueKey string
OutgoingQueueKey string OutgoingQueueKey string
RedisPrefix string
} }
func LoadConfig() *Config { func LoadConfig() *Config {
@ -21,6 +22,7 @@ func LoadConfig() *Config {
RedisPassword: getEnv("MQTT_REDIS_PASSWORD", ""), RedisPassword: getEnv("MQTT_REDIS_PASSWORD", ""),
IncomingQueueKey: getEnv("MQTT_INCOMING_QUEUE", "mqtt_incoming_jobs"), IncomingQueueKey: getEnv("MQTT_INCOMING_QUEUE", "mqtt_incoming_jobs"),
OutgoingQueueKey: getEnv("MQTT_OUTGOING_QUEUE", "mqtt_outgoing_commands"), OutgoingQueueKey: getEnv("MQTT_OUTGOING_QUEUE", "mqtt_outgoing_commands"),
RedisPrefix: getEnv("MQTT_REDIS_PREFIX", "starcloud_database_"),
} }
} }

View File

@ -39,7 +39,7 @@ func main() {
} }
// 加入 Laravel 前綴,確保雙方桶子同一個 // 加入 Laravel 前綴,確保雙方桶子同一個
prefixedIncomingKey := "starcloud_database_" + cfg.IncomingQueueKey prefixedIncomingKey := cfg.RedisPrefix + cfg.IncomingQueueKey
pusher := bridge.NewRedisPusher(rdb, prefixedIncomingKey) pusher := bridge.NewRedisPusher(rdb, prefixedIncomingKey)
mqttHandler := handler.NewMqttHandler(pusher) mqttHandler := handler.NewMqttHandler(pusher)
@ -76,7 +76,8 @@ func main() {
} }
// 3. 啟動 Redis Consumer (下行指令) // 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()) ctx, cancel := context.WithCancel(context.Background())
go consumer.Start(ctx) go consumer.Start(ctx)

View File

@ -7,8 +7,8 @@
# 依賴Docker (使用 eclipse-mosquitto 鏡像進行發送) # 依賴Docker (使用 eclipse-mosquitto 鏡像進行發送)
# ================================================================= # =================================================================
SERIAL_NO="SN00001" SERIAL_NO="M000001"
API_TOKEN="8QwOrmKX6sLmR5T1sChfvGjfc8eS4qaclOFd4ocItmeryii7SFqcC5uMpnzg" API_TOKEN="VfFFb0DIUqtLTPF4jyCsB2h5fWsMcVxCPboNHpKc3XzRComLEK07xFYRUzBJ"
TOPIC="machine/${SERIAL_NO}/heartbeat" TOPIC="machine/${SERIAL_NO}/heartbeat"
NETWORK="star-cloud_sail" NETWORK="star-cloud_sail"
BROKER_HOST="emqx" BROKER_HOST="emqx"

View File

@ -2,6 +2,14 @@ import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin'; import laravel from 'laravel-vite-plugin';
export default defineConfig({ export default defineConfig({
server: {
hmr: {
host: 'localhost',
},
host: '0.0.0.0',
port: 5175,
strictPort: true,
},
plugins: [ plugins: [
laravel({ laravel({
input: [ input: [