คำ |
ความหมาย (test) |
Brain |
evotech application |
Device |
อุปกรณ์ต่าง ๆ ของบริษัท evotech เช่น dimmer, switch, ม่าน และ เครื่องปรับอากาศ |
MQTT |
การเชื่อมต่อผ่าน protocol MQTT ซึ่งในบริบทของระบบ evotech คือโปรแกรม mosquitto |
App |
โปรแกรมภายนอกที่ต้องการเชื่อมต่อกับ Brain เพื่อควบคุมการทำงานของ device |
การเชื่อมต่อ
Brain จะมีการ broadcast message แบบ UDP ไปยัง multicast network interface ของ router (เช่น 192.168.1.255)
โดยในเนื้อของ message คือ mac address ของ brain ทำให้ทุกอุปกรณ์ที่ต่อ router ตัวเดียวกันสามารถรู้ IP address ของ brain
ได้จากการอ่าน message นี้
จากนั้น app ต้องต่อ MQTT มาที่ IP address ของ brain ที่ port 1883 ด้วย user และ password ที่กำหนด วิธีที่ app
เชื่อมต่อกับ brain ผ่าน MQTT จะมี 2 ลักษณะ คือ
- Request / Response ทำงานในลักษณะที่ app ส่ง message สั่งการ brain แล้ว brain ส่ง message ตอบกลับ แบบ 1 ต่อ 1 เช่น
การสั่งเปิดไฟและการสั่ง list devices
- Broadcast ทำงานในลักษณะที่เกิด event จาก device หรือตัว brain เอง แล้ว brain ส่ง message บอก app โดย app ไม่ต้องขอ
เช่น ความสว่างของหลอดไฟเปลี่ยน (เพราะคนปรับด้วย physical switch) หรือ device ขาดการติดต่อกับ brain
การส่งข้อมูลผ่าน MQTT จะใช้ topic naming convention ในลักษณะ direction
/source
/clientId
/refCode
โดยแต่ละส่วนมีความหมายดังนี้
คำ |
ความหมาย |
direction |
ประเภทของ message ได้แก่ evoRequest , evoResponse และ evoBroadcast |
source |
ประเภทของผู้เริ่มก่อให้เกิด operation ได้แก่ local สำหรับการส่งคำสั่งในวง LAN และ internet สำหรับการส่งคำสั่งผ่าน cloud server |
clientId |
รหัส client ซึ่งรหัสนี้ถูกกำหนดโดย app |
refCode |
รหัสอ้างอิง ใช้ภายใน app เอง เพื่อให้รู้ว่าการที่ระบบตอบกลับ เป็นการตอบ request ครั้งใด |
เช่น การส่งคำสั่งเปิดหลอดไฟ (dimmer) โดยผ่าน router ในบ้าน จะส่งคำสั่งไปที่ topic evoRequest
/local
/client001
/ref001
และระบบจะรายงานผลคำสั่งไปที่ topic evoResponse
/local
/client001
/ref001
และทันทีที่ dimmer ทำงาน dimmer
จะแจ้งสถานะล่าสุดกลับมาให้ brain ทราบ และ brain ก็จะ broadcast การเปลี่ยนสถานะของ dimmer ผ่าน topic evoBroadcast
ต่อไป (ไม่มี part /local/clientId/refCode
เนื่องจากเป็น event ที่เกิดจาก dimmer ไม่ใช่ app)
ภาพรวมคำสั่ง (ไม่อธิบายซ้ำใน section ถัดไป)
Request
- ทุก request จะมี header ซึ่งใน header จะมี token เป็น JSON Web Token (JWT) สำหรับตรวจสอบสิทธิ์ของผู้สั่ง
ซึ่งในปัจจุบันระหว่างการทำ PoC จะยังไม่มีการตรวจสอบ field นี้ แต่ app ยังจำเป็นต้องส่ง อาจส่งเป็น empty
string ก็ได้
- hwAddr คือ mac address ของ device เปรียบเสมือน key หรือชื่อที่ระบบใช้อ้างอิง
Response
โดยปกติ request แต่ละประเภทจะมี response แตกต่างกันออกไป แต่ในบางกรณีที่เกิดข้อผิดพลาด brain อาจตอบ error response
มาตรฐานต่อไปนี้ได้ โดยระบบจะส่ง response กลับไปที่ topic evoResponse
/local
/clientId
/refCode
ข้อผิดพลาด: คำสั่งผิด
เช่น ส่ง JSON ผิด format
{
"type": "BAD_INPUT",
"message": "Cannot deserialize value of type ..."
}
ข้อผิดพลาด: ระบบไม่รองรับคำสั่ง
เช่น ช่วง PoC อาจยังเปิด feature ไม่ครบ
{
"type": "UNSUPPORTED"
}
ข้อผิดพลาด: timeout
เช่น device ทำงานไม่ทัน แล้ว drop message หรือ มี app การอ้างถึง device ที่ไม่มีอยู่ในระบบ (จึงไม่มี device ใดตอบ)
โดยปกติ brain จะตั้งการ timeout ไว้ที่ 5 วินาที
{
"type": "TIMEOUT"
}
ประเภทข้อมูลมาตรฐาน (ทั่วไป)
type |
ค่าที่เป็นไปได้ |
Power |
ON , OFF และ DO_NOT_CHANGE |
Air Con Instruction Type |
NORMAL (สำหรับ device ที่สั่งงานตรง) และ IR_BOX (สำหรับ device ที่สั่งงานผ่านกล่อง infrared) |
Fan Speed |
AUTO , HIGH , MED , LOW และ DO_NOT_CHANGE |
AC Mode |
FAN , COOL , DRY , HEAT , AUTO และ DO_NOT_CHANGE |
Sweep Status |
ON , OFF , CHAR8 และ DO_NOT_CHANGE |
Motor Status |
STOP , UP , DOWN และ DO_NOT_CHANGE |
Percentage |
0 ถึง 100 เป็นจำนวนเต็มเท่านั้น |
Temperature |
15.0 ถึง 30.0 เป็นทศนิยม 1 ตำแหน่งเพิ่มลดทีละ 0.5 |
Decisecond |
ความยาว 1 ใน 10 ส่วนของวินาที เช่น 20 deciseconds คือ 2 วินาที |
DeviceControlResult
มีได้ 4 รูปแบบ ได้แก่ SUCCESSFUL, DROPPED, CANCELED และ FAILED
SUCCESSFUL
คือ device ทำงานตามคำสั่งสำเร็จด้วยดี
{
"type": "SUCCESSFUL"
}
DROPPED
คือ brain เลือกที่จะไม่ทำคำสั่งนี้ เพื่อป้องกัน device ทำงานไม่ทัน เช่น user เลื่อนแถบความสว่างจาก 0 ถึง 100 ในเวลา 2
วินาที กรณีนี้ brain จะ drop บางคำสั่งที่อยู่ตรงกลางระหว่าง 0 - 100
{
"type": "DROPPED"
}
CANCELED
คือ brain ยกเลิกคำสั่ง เนื่องจากมีคำสั่งอื่นที่ priority สูงกว่าแทรกเข้ามา (กรณีนี้ยังไม่มีการใช้ระหว่าง PoC)
{
"type": "CANCELED"
}
FAILED
{
"type": "FAILED",
"errorCode": ""
}
Device
มี 5 ประเภท แต่ในขั้นตอน PoC มี 4 ประเภท ได้แก่ dimmer, switch, air con และ curtain
Dimmer
{
"type": "DIMMER",
"power": "OFF",
"brightness": 0
}
Switch
{
"type": "SWITCH",
"power": "OFF"
}
Air Con
{
"type": "AIRCON",
"power": "ON",
"fanSpeed": "HIGH",
"acMode": "COOL",
"sweepStatus": "OFF",
"settingTemp": 18.0,
"roomTemp": 31.0
}
Curtain
{
"type": "CURTAIN",
"motorStatus": "STOP"
}
รายละเอียดคำสั่งแบบ Request / Response
app ต้องส่ง message (request) ไปที่ topic evoRequest
/source
/clientId
/refCode
และ ระบบจะตอบ (response) ไปที่
topic evoResponse
/source
/clientId
/refCode
โดย source
คือ "local" สำหรับการส่ง MQTT message ในวง LAN และ "internet" สำหรับการส่ง MQTT message ผ่าน cloud
server ส่วน clientId
และ refCode
app เป็นผู้กำหนดการใช้งานเอง
แสดงข้อมูล place
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"PLACE_GET" |
|
ตัวอย่าง
{
"type": "PLACE_GET",
"header": {
"token": "JWT"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"PLACE_GET" |
|
$.placeInfo.id |
UUID |
|
identity ของ place |
$.placeInfo.hwAddr |
string |
|
mac address ของกล่อง brain |
$.placeInfo.name |
string |
|
ชื่อที่ผู้ใช้ตั้ง |
ตัวอย่าง
{
"type": "PLACE_GET",
"placeInfo": {
"id": "7c5caeb4-ed9c-480f-8479-bbc735004653",
"hwAddr": "020180590B00",
"name": "Evotech Office"
}
}
แสดงรายการข้อมูล zone
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"ZONE_LIST" |
|
ตัวอย่าง
{
"type": "ZONE_LIST",
"header": {
"token": "JWT"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"ZONE_LIST" |
|
$.zoneInfos.id |
UUID |
|
identity ของ zone |
$.zoneInfos.name |
string |
|
ชื่อที่ผู้ใช้ตั้ง |
$.zoneInfos.deviceHwAddrs |
[ HwAddr ] |
|
device ใน zone |
ตัวอย่าง
{
"type": "ZONE_LIST",
"zoneInfos": [
{
"id": "21681f11-eb36-49e6-84ec-49c6a77edef6",
"name": "Basement",
"deviceHwAddrs": ["5CCF7F09D1C4", "5CCF7F363137", "5CCF7F362A3A"]
}
]
}
แสดงรายการข้อมูล scene
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"SCENE_LIST" |
|
ตัวอย่าง
{
"type": "SCENE_LIST",
"header": {
"token": "JWT"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"SCENE_LIST" |
|
$.sceneInfos.id |
UUID |
|
identity ของ scene |
$.sceneInfos.name |
string |
|
ชื่อที่ผู้ใช้ตั้ง |
$.sceneInfos.zoneId |
string |
|
zone ที่ scene นี้อยู่ |
ตัวอย่าง
{
"type": "SCENE_LIST",
"sceneInfos": [
{
"id": "12a68df3-eedb-4791-aa75-faa64e89066c",
"name": "All On",
"zoneId": "21681f11-eb36-49e6-84ec-49c6a77edef6"
},
{
"id": "dde66f7d-0cbb-4477-b603-b46c8f08d450",
"name": "All Off",
"zoneId": "21681f11-eb36-49e6-84ec-49c6a77edef6"
},
{
"id": "0719464e-008a-4b2f-b129-d95a475e332a",
"name": "Bedtime",
"zoneId": null
},
{
"id": "66ff6bf6-9d69-4bc1-89b0-ce8c1e74ee19",
"name": "Zone 1 - Movie Time",
"zoneId": "21681f11-eb36-49e6-84ec-49c6a77edef6"
}
]
}
แสดงรายการข้อมูล device
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_LIST" |
|
ตัวอย่าง
{
"type": "DEVICE_LIST",
"header": {
"token": "JWT"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_LIST" |
|
$.deviceInfos.hwAddr |
string |
|
mac address ของอุปกรณ์ |
$.deviceInfos.name |
string |
|
ชื่อที่ผู้ใช้ตั้ง |
$.deviceInfos.alive |
boolean |
|
ยังติดต่อกับ brain ได้หรือไม่ |
$.deviceInfos.lastSeen |
timestamp |
|
เวลาครั้งล่าสุดที่ device มีการตอบสนองกับ brain |
$.deviceInfos.device |
device |
|
รายละเอียด device (มีหลายประเภท) |
ตัวอย่าง
{
"type": "DEVICE_LIST",
"deviceInfos": [
{
"hwAddr": "5CCF7F362A3A",
"name": "Dimmer 1",
"alive": true,
"lastSeen": "2020-12-03T07:31:04.021Z",
"device": {
"type": "DIMMER",
"power": "OFF",
"brightness": 0
}
},
{
"hwAddr": "5CCF7F09CC8B",
"name": "แอร์ตัวหลัก",
"alive": true,
"lastSeen": "2020-12-03T07:31:04.094Z",
"device": {
"type": "AIRCON",
"power": "ON",
"fanSpeed": "HIGH",
"acMode": "COOL",
"sweepStatus": "OFF",
"settingTemp": 18.0,
"roomTemp": 31.0
}
}
]
}
ควบคุม dimmer
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.control.type |
fixed |
"DIMMER" |
|
$.control.power |
power |
|
|
$.control.brightness |
percentage |
|
ความสว่างของ dimmer |
$.control.duration |
decisecond |
|
เวลาที่ใช้ในการปรับความสว่างจาก ความสว่างเดิมไปยังความสว่างใหม่ (เปลี่ยนช้า ๆ) |
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"header": {
"token": "JWT"
},
"control": {
"type": "DIMMER",
"hwAddr": "5CCF7F36313E",
"power": "ON",
"brightness": 100,
"duration": 20
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.result |
DeviceControlResult |
|
|
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"result": {
"type": "SUCCESSFUL"
}
}
ควบคุม switch
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.control.type |
fixed |
"SWITCH" |
|
$.control.power |
power |
|
|
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"header": {
"token": "JWT"
},
"control": {
"type": "SWITCH",
"hwAddr": "000000000000",
"power": "OFF"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.result |
DeviceControlResult |
|
|
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"result": {
"type": "SUCCESSFUL"
}
}
ควบคุมเครื่องปรับอากาศ (air con)
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.control.type |
fixed |
"AIRCON" |
|
$.control.instructionType |
air con instruction type |
|
|
$.control.power |
power |
|
|
$.control.settingTemp |
temperature |
|
|
$.control.acMode |
AC mode |
|
|
$.control.fanSpeed |
fan speed |
|
|
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"header": {
"token": "JWT"
},
"control": {
"type": "AIRCON",
"hwAddr": "5CCF7F09CC8B",
"instructionType": "NORMAL",
"power": "OFF",
"settingTemp": 25,
"acMode": "COOL",
"fanSpeed": "AUTO"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.result |
DeviceControlResult |
|
|
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"result": {
"type": "SUCCESSFUL"
}
}
ควบคุมม่าน (curtain)
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.control.type |
fixed |
"CURTAIN" |
|
$.control.motorStatus |
motor status |
|
ไม่มีการสั่งว่าเปิดหรือปิดถึงจุดใด มีแค่สั่งเปิด ปิด และ หยุด |
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"header": {
"token": "JWT"
},
"control": {
"type": "CURTAIN",
"hwAddr": "DEVICE",
"motorStatus": "STOP"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.result |
DeviceControlResult |
|
|
ตัวอย่าง
{
"type": "DEVICE_CONTROL",
"result": {
"type": "SUCCESSFUL"
}
}
ควบคุม scene
Request
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"SCENE_RUN" |
|
$.cmd.sceneId |
UUID |
|
scene ที่ต้องการควบคุม |
$.cmd.mode |
scene run mode |
|
ON คือเล่น scene ตามที่ตั้งค่า, OFF คือปิดทุก device ที่มีการตั้งค่าใน scene, และ TOGGLE คือสลับสถานะ scene จาก ON เป็น OFF และ OFF เป็น ON |
ตัวอย่าง
{
"type": "SCENE_RUN",
"header": {
"token": "JWT"
},
"cmd": {
"sceneId": "dde66f7d-0cbb-4477-b603-b46c8f08d450",
"mode": "ON"
}
}
Response
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_CONTROL" |
|
$.result.type |
scene run result |
|
มี 4 ประเภท ได้แก่ SUCCESSFUL (สำเร็จ), PARTIALLY_SUCCESSFUL (สำเร็จบางส่วน), NOT_FOUND (ไม่พบ scene) และ TIMEOUT (device ไม่ตอบสนอง) |
ตัวอย่าง
{
"type": "SCENE_RUN",
"result": {
"type": "SUCCESSFUL"
}
}
รายละเอียดการ broadcast
กรณีที่ข้อมูล place มีการเปลี่ยนแปลง
Topic
ระบบจะ broadcast ไปที่ topic ชื่อ evoBroadcast
/source
/clientId
/refCode
โดยค่าของ source
, clientId
และ refCode
ขึ้นอยู่กับว่าผู้ที่ทำให้เกิดการเปลี่ยนแปลงได้กระทำการจากช่องทางใด (เช่น เปลี่ยนชื่อ place ผ่าน evotech
mobile app)
โครงสร้าง
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"PLACE_INFO_UPDATED" |
|
$.placeInfo.id |
UUID |
|
identity ของ place |
$.placeInfo.hwAddr |
string |
|
mac address ของกล่อง brain |
$.placeInfo.name |
string |
|
ชื่อที่ผู้ใช้ตั้ง |
ตัวอย่าง
{
"type": "PLACE_INFO_UPDATED",
"placeInfo": {
"id": "7c5caeb4-ed9c-480f-8479-bbc735004653",
"hwAddr": "020180590B00",
"name": "Evotech Office"
}
}
กรณีที่ข้อมูล device มีการเปลี่ยนแปลง
Topic
ระบบจะ broadcast ไปที่ topic ชื่อ evoBroadcast
ไม่มี part ที่เหลือ เนื่องจากเป็นการเปลี่ยนแปลงที่เกิดจากตัว device เอง
โครงสร้าง
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"DEVICE_STATUS_UPDATED" |
|
$.deviceInfo.name |
string |
|
ชื่อที่ผู้ใช้ตั้ง |
$.deviceInfo.alive |
boolean |
|
ยังติดต่อกับ brain ได้หรือไม่ |
$.deviceInfo.lastSeen |
timestamp |
|
เวลาครั้งล่าสุดที่ device มีการตอบสนองกับ brain |
$.deviceInfo.device |
device |
|
รายละเอียด device (มีหลายประเภท) |
ตัวอย่าง
{
"type": "DEVICE_STATUS_UPDATED",
"deviceInfo": {
"hwAddr": "5CCF7F362A3A",
"name": "Dimmer 1",
"alive": true,
"lastSeen": "2020-12-03T07:40:10.291Z",
"device": {
"type": "DIMMER",
"power": "ON",
"brightness": 100
}
}
}
กรณีที่ device ขาดการติดต่อ
Topic
ระบบจะ broadcast ไปที่ topic ชื่อ evoBroadcast
ไม่มี part ที่เหลือ เนื่องจากเป็นการเปลี่ยนแปลงที่เกิดจากตัว device เอง
โครงสร้าง
Field |
Type |
Value (only if fixed) |
Description |
$.type |
fixed |
"NEW_DEAD_DEVICES" |
|
$.hwAddrs |
[ HwAddr ] |
|
device ที่ขาดการติดต่อ |
ตัวอย่าง
{
"type": "NEW_DEAD_DEVICES",
"hwAddrs": ["5CCF7F362A3A", "5CCF7F09CC8B"]
}