เป้าหมายการเชื่อม
- Kiosk / Web สั่งเริ่ม–หยุด Auto Step, โหลดสูตร (PO + เป้าน้ำหนัก 6 ช่อง) ลง PLC
- SCADA แสดงสถานะจริง: วาล์ว, Blower, น้ำหนัก Load cell, Alarm
- WeightSystem DB บันทึกเวลาเริ่ม–จบ, น้ำหนักจริง →
product_detail_control_mc, product_detail
- ย้อนกลับได้ หยุดฉุกเฉิน (E-Stop) จาก SCADA/Kiosk ส่งถึง PLC ทันที
แนะนำ Protocol: PLC ↔ Gateway ใช้ OPC UA หรือ Modbus TCP ·
Gateway ↔ IT ใช้ MQTT (โครงสร้างเดิมในโปรเจกต์มี mqttweight.php, meter.php แล้ว)
สถาปัตยกรรม 3 ชั้น
ชั้น Field (Plant)
PLC / Load cell
Side blower 1.5 kW ×6
Ring blower 7.5 kW
Knife gate, Rotary feed
Bigbag 550 kg + Hopper ล่าง/บน
ชั้น SCADA / Gateway
Ignition / WinCC / Node-RED
OPC UA Server / MQTT Bridge
Alarm, Trend, Mimic HMI
ไม่ให้ Web เข้า PLC โดยตรง
ชั้น IT (WeightSystem)
PHP Kiosk + API
MSSQL smartweight
MQTT Subscriber service
รายงาน / สูตร frontformula
flowchart TB
subgraph FIELD["ชั้น Field"]
PLC[PLC สถานี 1-6 + Common]
LC[Load Cell]
VAL[Valves / Blowers]
PLC --> LC
PLC --> VAL
end
subgraph SCADA["ชั้น SCADA"]
GW[OPC-MQTT Gateway]
HMI[SCADA HMI]
ALM[Alarm Historian]
HMI --> GW
GW --> ALM
end
subgraph IT["ชั้น IT — WeightSystem"]
KIOSK[Kiosk / prepare_* pages]
API[PHP API scada_bridge]
DB[(MSSQL)]
MQIN[MQTT Subscriber]
KIOSK --> API
API --> DB
MQIN --> DB
API --> MQOUT[MQTT Publish]
end
PLC <-->|OPC UA / Modbus| GW
GW <-->|MQTT| MQOUT
GW <-->|MQTT| MQIN
KIOSK -.->|HTTPS| API
โครงสร้าง Tag (MQTT Topic)
รูปแบบ: smartweight/prepare/line1/{station}/{signal} · QoS 1 สำหรับคำสั่ง · Retain สำหรับสถานะล่าสุด
สถานี 1–6 (ต่อชุด)
| Signal | Topic suffix | ชนิด | คำอธิบาย |
| น้ำหนักจริง | .../wt_actual | float, retain | kg จาก Load cell |
| เป้าหมาย | .../wt_target | float | จากสูตร / Kiosk |
| สถานะสถานี | .../state | int enum | 0=Idle 1=Suck 2=Transfer 3=Weigh 4=Done 5=Fault |
| Side blower | .../blower_run | bool | Pressure ล่าง |
| Knife gate | .../gate_open | bool | Hopper บน |
| Rotary feed | .../rotary_run | bool | ปล่อยลงสายรวม |
| Fault code | .../fault | int | 0=ปกติ |
Common (ทั้งไลน์)
| Signal | Topic | ชนิด |
| สถานะ Auto Step รวม | smartweight/prepare/line1/common/auto_step | int 0–8 ตาม Kiosk |
| คำสั่งจาก Kiosk | .../common/cmd | JSON: start|pause|estop|reset |
| PO / Batch | .../common/recipe | JSON: order, batch, targets[6] |
| Vacuum blower | .../common/vacuum_run | bool |
| Hopper 500L น้ำหนัก | .../common/hopper500_wt | float |
| E-Stop | .../common/estop | bool, retain, highest priority |
ความจุ Load cell ต่อสถานี
| สถานี | Max (kg) | Tolerance แนะนำ |
| #1 |
100 |
±0.2 kg |
| #2 |
100 |
±0.2 kg |
| #3 |
300 |
±0.5 kg |
| #4 |
100 |
±0.2 kg |
| #5 |
1000 |
±1.0 kg |
| #6 |
500 |
±0.5 kg |
จับคู่ Auto Step (Web) ↔ PLC ↔ SCADA
| หน้า Kiosk / รายงาน | PLC State | SCADA แสดง |
INIT |
ST_IDLE |
System Ready |
SELECT_PO |
ST_RECIPE_LOAD |
Recipe Loaded |
PRESSURE |
ST_SUCK |
Pressure / Suck |
LIFT |
ST_TRANSFER |
Pneumatic Transfer |
WEIGH |
ST_WEIGH |
Weighing |
DISCHARGE |
ST_DISCHARGE |
Discharge to Line |
VACUUM |
ST_VACUUM |
Vacuum Collect |
MIX |
ST_MIX_FEED |
Mixer Feed |
sequenceDiagram
participant K as Kiosk Web
participant A as PHP API
participant M as MQTT Broker
participant G as SCADA Gateway
participant P as PLC
K->>A: POST /cmd start + recipe
A->>M: publish common/cmd + recipe
M->>G: forward
G->>P: OPC write targets + start
loop แต่ละสถานี 1-6
P->>G: state=Suck/Transfer/Weigh
G->>M: publish station/state, wt_actual
M->>A: subscriber บันทึก DB
A->>K: WebSocket/SSE อัปเดต UI
end
P->>G: state=Done, discharge
G->>M: vacuum + hopper500
A->>A: INSERT product_detail_control_mc
ฐานข้อมูล WeightSystem (เสนอเพิ่ม)
| ตาราง | หน้าที่ |
scada_tag_map |
แมป topic ↔ คอลัมน์/สถานี · แก้ Tag โดยไม่แก้โค้ด |
scada_event_log |
บันทึกทุก message (เวลา, topic, payload, quality) |
prepare_batch_run |
1 รอบ Auto: PO, ผู้สั่ง, เวลาเริ่ม–จบ, สถานะรวม |
prepare_batch_station |
ต่อรอบ×สถานี: target_kg, actual_kg, start/end, state |
เมื่อจบชั่ง → sync ไป product_detail_control_mc (มีอยู่) และ product_detail ผ่าน pd_id |
API เสนอ (PHP)
| Method | Endpoint | คำอธิบาย |
| POST | /api/prepare/cmd | start | pause | reset | estop |
| POST | /api/prepare/recipe | โหลด PO, Batch, targets[6] แล้ว publish MQTT |
| GET | /api/prepare/status | สถานะล่าสุด 6 สถานี + common (จาก cache/DB) |
| GET | /api/prepare/history | รายการรอบย้อนหลัง → ลิงก์รายงาน mixer |
ความปลอดภัย & โซนเครือข่าย
- OT Zone: PLC, Load cell, Gateway — ไม่มี Internet outbound
- DMZ: MQTT Broker, OPC UA Gateway เท่านั้น
- IT Zone: PHP / MSSQL — subscribe MQTT ทางเดียว (ไม่ bind PLC port)
- MQTT: TLS + user/password แยก
kiosk_pub / scada_pub / itsub (read-only)
- E-Stop: วง hardware PLC + tag
estop retain — Kiosk ส่งซ้ำได้แต่ไม่แทนที่ hardware
แผนดำเนินงาน (Roadmap)
1
กำหนด Tag & สถาปัตยกรรม
(~2–3 สัปดาห์)
- ผัง Tag 6 สถานี + Common
- เลือก Protocol (MQTT + OPC UA)
- Zone ความปลอดภัย
2
Gateway / MQTT Broker
(~3–4 สัปดาห์)
- MQTT Broker (on-prem)
- Node-RED หรือ Ignition MQTT Engine
- ทดสอบ read/write tag
3
เชื่อม WeightSystem
(~4–6 สัปดาห์)
- ตาราง scada_* ใน DB
- API รับคำสั่ง Kiosk
- บันทึก product_detail_control_mc
4
SCADA HMI + ทดสอบรวม
(~4–6 สัปดาห์)
- หน้าจอ SCADA mimic
- Alarm / Trend
- FAT / SAT
สรุปสำหรับนำเสนอ
- อย่าให้ PHP คุยกับ PLC โดยตรง — ใช้ SCADA Gateway + MQTT ตรงกับที่ระบบมี MQTT อยู่แล้ว
- นิยาม Tag / Topic ให้ตรง 6 สถานี + common ก่อนเขียนโค้ด
- จับ Auto Step บน Kiosk กับ state PLC ให้ตรงกัน (ตารางด้านบน)
- บันทึกผลลง product_detail_control_mc เมื่อจบแต่ละรอบ — ใช้รายงานเดิมได้ทันที
- ทำทีละ Phase: Tag → Broker → API → HMI ทดสอบรวม
ขั้นถัดไปที่พร้อม implement: สร้างตาราง prepare_batch_*, MQTT subscriber service,
และปุ่ม Kiosk บน prepare_weighing_system.php เรียก API จริง