สารบัญ
- ทำไมเส้นทาง SNS แบบปกติถึงยุ่งยาก
- สิ่งที่ต้องมี
- ขั้นที่ 1 — สร้างช่องที่ดัง
- ขั้นที่ 2 — สร้าง connection และ API destination
- ขั้นที่ 3 — สร้างกฎและ input transformer
- ขั้นที่ 4 — รู้ว่าอีเวนต์หน้าตาเป็นอย่างไรจริง ๆ
- ขั้นที่ 5 — กรองให้เหลือเฉพาะสิ่งที่คู่ควรกับสายโทรเข้า
- ขั้นที่ 6 — เปิดประตูที่เงียบกว่าให้การกลับสู่ปกติ
- ทดสอบก่อนจะไว้ใจ
- แล้ว SNS กับการส่งอีเมลเพื่อให้โทรล่ะ
- ขีดจำกัดที่สำคัญระหว่างเกิดเหตุ
- สิ่งที่การตั้งค่านี้ไม่ได้ให้
- การแก้ปัญหา
- คำถามที่พบบ่อย
- CloudWatch โทรไปยังเบอร์โทรศัพท์เองได้ไหม
- ต้องมี SNS topic ไหม
- CloudWatch alarm ทะลุโหมดห้ามรบกวนไหม
- ทำไมไม่สมัคร URL เว็บฮุกเข้ากับ SNS ไปเลย
- ใช้ AWS แล้วมีค่าใช้จ่ายไหม
- โทรหาคนละคนสำหรับ alarm ต่างกันได้ไหม
- แล้ว alarm ในหลายรีเจียนหรือหลายบัญชีล่ะ
- สรุป
- บทความที่เกี่ยวข้อง
CloudWatch alarm โทรหาคุณไม่ได้ แอ็กชันในตัวมีแค่ SNS, Auto Scaling, EC2 และ Systems Manager ส่วน SNS ก็จบที่อีเมล SMS หรือคิวที่คุณต้องคอยเฝ้าดู บทความสอนที่พาไปถึงโทรศัพท์ที่ดังได้จริงมักให้ตั้งฟังก์ชัน Lambda และบัญชี Twilio คุณข้ามได้ทั้งสองอย่าง ให้ EventBridge รับการเปลี่ยนสถานะของ alarm แล้วแปลงเป็น JSON ก้อนเล็ก ๆ จากนั้น POST ไปยังช่องแบบโทรเข้าของ Echobell
คู่มือนี้ครอบคลุมเส้นทางทั้งหมด: ช่อง กฎของ EventBridge input transformer ตัวกรองที่ทำให้เสียงเรียกเข้ายังมีความหมาย และเหตุผลที่การชี้ SNS ตรงไปที่เว็บฮุกดูเหมือนน่าจะใช้ได้ แต่ส่วนใหญ่ใช้ไม่ได้
ทำไมเส้นทาง SNS แบบปกติถึงยุ่งยาก
คำแนะนำมาตรฐานคือ "alarm → SNS topic → subscriber" สำหรับการโทรเข้า มันมีสามปัญหา:
- SNS ไม่มีโปรโตคอลเสียง ประเภทผู้สมัครรับมีอีเมล, SMS, พุชมือถือ, SQS, Lambda, Firehose และ HTTP(S) SMS พลาดง่ายและถูกโหมดห้ามรบกวนบล็อก ส่วนการโทรด้วยเสียงต้องมีบางอย่างที่คุณสร้างเอง
- ข้อความ HTTPS เป็นสตริงซ้อนสตริง SNS ส่งซองของมันมาด้วย
Content-Type: text/plainและตัว alarm เป็นเอกสาร JSON ที่ถูกแปลงเป็นสตริงอยู่ในฟิลด์Messageของซอง ตัวรับเว็บฮุกที่อ่านเป็นฟิลด์ —AlarmName,NewStateValue— จะเจอแค่ก้อนเดียวที่อ่านไม่ออก - ซองมีขนาดใหญ่ ด้วยลายเซ็น URL ใบรับรอง และลิงก์ยกเลิกการสมัคร ซองจึงเพิ่มข้อมูลมากกว่าหนึ่งกิโลไบต์ก่อนข้อความของ alarm จะเริ่ม Echobell ตัดเนื้อหาการแจ้งเตือนที่ 1500 ไบต์ เทมเพลตแบบ "เทบอดี้ทั้งก้อน" จึงถูกตัดตรงจุดที่ส่วนมีประโยชน์เริ่มพอดี
คุณทำให้ SNS ใช้ได้ด้วย Lambda ที่แกะข้อความแล้วส่งต่อ แต่ CloudWatch ส่งทุกการเปลี่ยนสถานะของ alarm ไปยัง EventBridge เป็นอีเวนต์ JSON ที่สะอาดอยู่แล้ว — ไม่ต้องตั้งแอ็กชันใด ๆ — และ EventBridge ก็แปลงรูปแล้วเรียกปลายทาง HTTPS ได้เอง
สิ่งที่ต้องมี
- บัญชี AWS และสิทธิ์สร้างกฎของ EventBridge, connection และ API destination
- ติดตั้ง Echobell แล้ว (App Store / Google Play)
- CloudWatch alarm ที่มีอยู่แล้วอย่างน้อยหนึ่งตัว
- เวลาสิบนาที
ฝั่งคุณไม่ต้องมีอะไรรับทราฟฟิกขาเข้าเลย EventBridge เป็นฝ่ายยิงคำขาออก
ขั้นที่ 1 — สร้างช่องที่ดัง
ใน Echobell สร้างช่องใหม่แล้วตั้งประเภทการแจ้งเตือนเป็น โทรเข้า (Calling) ช่องแบบโทรเข้าทำงานเหมือนสายเรียกเข้า ไม่ใช่การแจ้งเตือนแบบพุช จึงทะลุโหมดโฟกัสและห้ามรบกวนของ iOS ได้
transformer ในขั้นที่ 3 ส่งบอดี้แบบแบนที่มีฟิลด์ alarm, state, reason, region และ link เทมเพลตจึงสั้นได้:
หัวเรื่อง: {{state}}: {{alarm}}
เนื้อหา: {{reason}}
ตั้ง เทมเพลตลิงก์ ในการตั้งค่าขั้นสูง เพื่อให้แตะการแจ้งเตือนแล้วเปิด alarm ในคอนโซลได้ทันที:
{{link}}
คัดลอก URL เว็บฮุกของช่องจากหน้ารายละเอียดช่อง:
https://hook.echobell.one/t/<channel-token>
ขั้นที่ 2 — สร้าง connection และ API destination
EventBridge เรียกปลายทาง HTTPS ภายนอกผ่าน API destination ซึ่งต้องมี connection สำหรับเก็บข้อมูลยืนยันตัวตน Echobell ยืนยันตัวตนด้วยโทเคนลับใน URL connection จึงเป็นแค่พิธีกรรม — แต่ EventBridge ไม่ยอมสร้าง destination ถ้าไม่มี
- เปิด EventBridge → Integration → API destinations → Connections → Create connection
- Name:
echobell - Authorization type: API key
- API key name:
x-source, Value:eventbridge - สร้างให้เสร็จ แล้วไปที่ API destinations → Create API destination
- Name:
echobell-calling - API destination endpoint: URL ช่อง Echobell จากขั้นที่ 1
- HTTP method:
POST - Invocation rate limit:
1ต่อวินาทีก็เหลือเฟือ และทำหน้าที่เป็นวาล์วนิรภัย - Connection:
echobell
เฮดเดอร์ API key จะถูกส่งไปกับทุกคำขอ คุณตรวจมันได้ในเงื่อนไขของช่อง Echobell ถ้าอยากมีด่านที่สองก่อนถึงโทเคน:
header["x-source"] == "eventbridge"
ขั้นที่ 3 — สร้างกฎและ input transformer
ไปที่ EventBridge → Rules → Create rule ในรีเจียนเดียวกับ alarm กฎเป็นแบบรายรีเจียน alarm ใน eu-west-1 มองไม่เห็นจากกฎใน us-east-1
ใช้ event bus แบบ default และกฎแบบ event pattern แพตเทิร์นนี้จับทุก alarm ที่เปลี่ยนเป็น ALARM:
{
"source": ["aws.cloudwatch"],
"detail-type": ["CloudWatch Alarm State Change"],
"detail": {
"state": { "value": ["ALARM"] }
}
}
สำหรับเป้าหมาย เลือก EventBridge API destination แล้วเลือก echobell-calling ให้คอนโซลสร้าง execution role ใหม่ให้ — มันให้สิทธิ์ events:InvokeApiDestination สำหรับ destination นี้เท่านั้น ไม่มีอย่างอื่น
จากนั้นขยาย Additional settings → Configure target input → Input transformer:
Input path
{
"alarm": "$.detail.alarmName",
"state": "$.detail.state.value",
"reason": "$.detail.state.reason",
"region": "$.region",
"time": "$.time"
}
Template
{
"alarm": "<alarm>",
"state": "<state>",
"reason": "<reason>",
"region": "<region>",
"time": "<time>",
"link": "https://console.aws.amazon.com/cloudwatch/home?region=<region>#alarmsV2:alarm/<alarm>"
}
EventBridge ส่งผลลัพธ์เป็น application/json ซึ่งทำให้ Echobell อ่าน {{alarm}} และ {{state}} ได้โดยตรง
ขั้นที่ 4 — รู้ว่าอีเวนต์หน้าตาเป็นอย่างไรจริง ๆ
input path อ่านจากอีเวนต์ที่ CloudWatch เผยแพร่ แบบย่อแล้วเป็นดังนี้:
{
"version": "0",
"id": "c4c1c1c9-6542-e61b-6ef0-8c4d36933a92",
"detail-type": "CloudWatch Alarm State Change",
"source": "aws.cloudwatch",
"account": "123456789012",
"time": "2026-10-16T03:12:44Z",
"region": "us-east-1",
"resources": ["arn:aws:cloudwatch:us-east-1:123456789012:alarm:prod-api-5xx"],
"detail": {
"alarmName": "prod-api-5xx",
"state": {
"value": "ALARM",
"reason": "Threshold Crossed: 1 out of the last 1 datapoints [42.0] was greater than the threshold (10.0).",
"timestamp": "2026-10-16T03:12:44.000+0000"
},
"previousState": { "value": "OK" },
"configuration": { "description": "API 5xx errors on the prod load balancer" }
}
}
เรื่องที่ควรรู้ก่อนแก้เทมเพลต:
- alarm อยู่ใต้
detail$.alarmNameไม่ตรงกับอะไรเลย ส่วน$.detail.alarmNameตรง state.reasonเป็นข้อความที่ระบบสร้างขึ้น มันระบุจุดข้อมูลและเกณฑ์ ซึ่งคือสิ่งที่คุณอยากได้ยินตอนตีสามพอดี- ชื่อ alarm ถูกใส่เข้าไปตามตัวอักษร เครื่องหมายอัญประกาศคู่ในชื่อ alarm หรือในเหตุผลจะทำให้ JSON ที่ transformer สร้างพัง ใช้แค่ตัวอักษร ตัวเลข ขีดกลาง และขีดล่างในชื่อ alarm — ซึ่งเป็นแนวปฏิบัติที่ดีอยู่แล้ว — ไม่เช่นนั้นการโทรจะล้มเหลวด้วยข้อผิดพลาด 400
- ลิงก์ต้องใช้ชื่อธรรมดา ชื่อที่มีช่องว่างหรือ
#จะลิงก์ลึกได้ไม่ถูกต้อง แต่การค้นหาในคอนโซลยังหาเจออยู่
ขั้นที่ 5 — กรองให้เหลือเฉพาะสิ่งที่คู่ควรกับสายโทรเข้า
ช่อง alarm ที่ดังทุกครั้งที่เป็น ALARM คือวิธีที่เร็วที่สุดที่จะฝึกตัวเองให้เมินมัน ให้กรองสองจุด
ในแพตเทิร์นของ EventBridge ซึ่งทำงานก่อนที่อะไรจะถูกส่งออกไป:
| เป้าหมาย | สิ่งที่เปลี่ยนในแพตเทิร์น |
|---|---|
| เฉพาะ alarm ของโปรดักชัน | "alarmName": [{ "prefix": "prod-" }] ภายใน detail |
| ข้ามทุกอย่างที่ติดป้ายว่าไม่เร่งด่วน | ตั้งชื่อเป็น warn-… แล้วใช้ "alarmName": [{ "anything-but": { "prefix": "warn-" } }] |
| เฉพาะ alarm ที่ระบุ | "alarmName": ["prod-api-5xx", "prod-db-cpu"] |
| เฉพาะ alarm จริง ไม่เอาสถานะทดสอบ | คง "state": { "value": ["ALARM"] } ไว้ — อีเวนต์ INSUFFICIENT_DATA ไม่มีทางตรง |
| เฉพาะบัญชีหรือรีเจียนเดียว | เพิ่ม "account": ["123456789012"] หรือ "region": ["us-east-1"] ที่ระดับบนสุด |
ฝั่ง Echobell ใช้เงื่อนไขของช่องสำหรับสิ่งที่แพตเทิร์นแสดงออกไม่ได้ เช่นช่วงเวลา:
state == "ALARM" && (hour >= 17 || hour < 9)
ตัวแปรเวลาของ Echobell เป็น UTC จึงควรแปลงจากเขตเวลาของคุณก่อน รายการตัวแปรทั้งหมดอยู่ในคู่มืออ้างอิงเงื่อนไข
ขั้นที่ 6 — เปิดประตูที่เงียบกว่าให้การกลับสู่ปกติ
กฎข้อที่สองที่มี "value": ["OK"] บอกคุณได้ว่าปัญหาหายแล้วโดยไม่ต้องดังเสียงเรียกเข้า สร้างช่อง Echobell ช่องที่สองเป็นประเภท สำคัญตามเวลา (Time Sensitive) (หรือแบบปกติ) สร้าง API destination ตัวที่สองชี้ไปที่ช่องนั้น แล้วใช้ input transformer ตัวเดิมซ้ำ เทมเพลตหัวเรื่อง {{state}}: {{alarm}} จะอ่านออกมาเป็น "OK: prod-api-5xx" อยู่แล้ว
| กฎ | สถานะ | ประเภทช่อง | พฤติกรรม |
|---|---|---|---|
alarms-to-call | ALARM, คำนำหน้า prod- | โทรเข้า | ดังทะลุโหมดโฟกัส |
alarms-warn | ALARM, คำนำหน้า warn- | สำคัญตามเวลา | ขึ้นหน้าจอล็อก ไม่ส่งเสียง |
alarms-recovered | OK | ปกติ | พุชธรรมดา |
ทดสอบก่อนจะไว้ใจ
อย่ารอให้โปรดักชันพังก่อน บังคับ alarm ให้เข้าสู่สถานะที่ต้องการ:
aws cloudwatch set-alarm-state \
--alarm-name prod-api-5xx \
--state-value ALARM \
--state-reason "Manual test of the Echobell path"
alarm จะกลับสู่สถานะจริงในการประเมินรอบถัดไป แต่อีเวนต์การเปลี่ยนสถานะนั้นเป็นของจริงและผ่านกฎของคุณ หากต้องการทดสอบเฉพาะฝั่ง Echobell ให้ยิงช่องโดยตรง:
curl -X POST https://hook.echobell.one/t/<channel-token> \
-H 'Content-Type: application/json' \
-d '{"alarm":"prod-api-5xx","state":"ALARM","reason":"Manual test","region":"us-east-1","link":"https://console.aws.amazon.com/cloudwatch/"}'
ถ้า curl ดังแต่การทดสอบ alarm ไม่ดัง ปัญหาอยู่ที่กฎ transformer หรือ destination — ไม่ใช่ที่ช่อง
แล้ว SNS กับการส่งอีเมลเพื่อให้โทรล่ะ
ถ้าคุณมี SNS topic อยู่ทุกที่แล้วและไม่อยากแตะ EventBridge ยังมีอีกสองเส้นทาง:
- SNS → Lambda → เว็บฮุก โค้ดไม่กี่บรรทัดแยกวิเคราะห์
Messageแล้ว POST บอดี้แบบแบนไปยัง URL Echobell เดิม ใช้ได้ แต่คุณต้องดูแลฟังก์ชัน role และล็อกของมันเพิ่มขึ้นมา - SNS → อีเมล → อีเมลทริกเกอร์ของ Echobell สมัครที่อยู่อีเมลทริกเกอร์ของช่องเข้ากับ topic alarm จะมาถึงเป็นอีเมล และ
{{subject}}กับ{{text}}ในเทมเพลตจะกลายเป็นการแจ้งเตือน นี่คือตัวเลือกที่ตั้งค่าน้อยที่สุด โดยมีข้อแม้ว่าการสมัครอีเมลของ SNS ต้องคลิกยืนยันหนึ่งครั้ง และข้อความจะไม่ถูกแปลงรูป
การสมัคร URL เว็บฮุกของ Echobell เข้ากับ topic โดยตรงเป็นปลายทาง HTTPS คือเส้นทางที่ควรเลี่ยง: คำขอยืนยันจะมาถึงเป็นการแจ้งเตือน และ alarm ทุกตัวหลังจากนั้นก็คือซองยาว ๆ ที่อธิบายไว้ข้างต้น
ขีดจำกัดที่สำคัญระหว่างเกิดเหตุ
- บอดี้ 1 MiB Echobell ปฏิเสธบอดี้ของทริกเกอร์ที่เกิน 1 MiB ด้วย HTTP 413 alarm ที่ผ่านการแปลงมีขนาดไม่กี่ร้อยไบต์ คุณจึงไม่ชนขีดจำกัดนี้ที่นี่
- 120 คำขอต่อนาทีต่อโทเคน เกินกว่านั้นทริกเกอร์จะตอบ
429พร้อมRATE_LIMIT_EXCEEDEDและRetry-Afterขีดจำกัดของ destination ที่ 1 ต่อวินาทีทำให้คุณอยู่ใต้เพดาน และ EventBridge จะลองส่งใหม่กับอีเวนต์ที่ส่งไม่สำเร็จ - เนื้อหาการแจ้งเตือน 1500 ไบต์ ที่ยาวกว่านั้นจะถูกตัด
state.reasonยาวหนึ่งถึงสองประโยคและพอดี
สิ่งที่การตั้งค่านี้ไม่ได้ให้
- ไม่มีการตอบรับ (ack) การรับสายไม่ได้บอกอะไร CloudWatch และไม่ได้ปิดเสียงผู้สมัครรับคนอื่น
- ไม่มีการยกระดับหรือหมุนเวร ทุกคนที่สมัครรับช่องจะได้รับสาย ไม่มีใครเป็นคนถัดไป
- ไม่มีการตัดซ้ำนอกเหนือจากตัว alarm เอง alarm ที่สถานะกระพริบ
OK → ALARMทุกไม่กี่นาทีจะดังทุกครั้ง แก้ได้ด้วยการเพิ่มช่วงการประเมินให้นานขึ้นหรือใช้DatapointsToAlarmที่ตัว alarm เอง - ไม่มีการซิงก์สองทาง การแก้ที่ต้นเหตุไม่ได้ล้างอะไรบนโทรศัพท์ของคุณ
ถ้าข้อเหล่านี้รับไม่ได้ คุณต้องการแพลตฟอร์มออนคอลเต็มรูปแบบ แต่ถ้าสิ่งที่คุณต้องการคือ "โทรหาฉันเมื่อ alarm ของโปรดักชันทำงาน" นี่ก็คือคอนโซลไม่กี่หน้าจอ
การแก้ปัญหา
alarm ทำงานแต่ไม่มีอะไรมาถึง เปิดแท็บ Monitoring ของกฎ: Invocations บอกว่าแพตเทิร์นตรงหรือไม่ FailedInvocations บอกว่าการส่งล้มเหลวหรือไม่ กฎที่อยู่คนละรีเจียนกับ alarm จะไม่มีวันตรง
กฎตรงแต่การโทรล้มเหลวด้วย 400 transformer สร้าง JSON ที่ไม่ถูกต้อง มองหาเครื่องหมายอัญประกาศหรือแบ็กสแลชในชื่อ alarm หรือเหตุผล
การแจ้งเตือนว่างเปล่า เทมเพลตกำลังอ่านฟิลด์ที่ transformer ไม่ได้ส่ง บอดี้เป็นแบบแบน: {{alarm}} ไม่ใช่ {{detail.alarmName}}
ดังซ้ำ ๆ จาก alarm เดียว alarm กำลังกระพริบ เพิ่มช่วงการประเมินให้ยาวขึ้นหรือกำหนดให้ต้องมีจุดข้อมูลมากขึ้น นี่เป็นการตั้งค่าของ CloudWatch ไม่ใช่ของ Echobell
ดังจาก alarm ที่ไม่ได้คาดไว้ ตรวจว่าแพตเทิร์นขาดตัวกรอง prefix หรือเปล่า และจำไว้ว่า composite alarm และ alarm ที่สร้างโดยเครื่องมืออื่น (เช่นนโยบาย Auto Scaling) ก็ปล่อยการเปลี่ยนสถานะเช่นกัน
คำถามที่พบบ่อย
CloudWatch โทรไปยังเบอร์โทรศัพท์เองได้ไหม
ไม่ได้ แอ็กชันของ CloudWatch alarm คือการแจ้งเตือนผ่าน SNS, Auto Scaling, แอ็กชันของ EC2 และ Systems Manager การโทรด้วยเสียงต้องอาศัยบริการภายนอก ไม่ว่าจะเป็น Lambda ที่โทรผ่านผู้ให้บริการ แพลตฟอร์มออนคอล หรือเว็บฮุกแบบโทรเข้าอย่าง Echobell
ต้องมี SNS topic ไหม
ไม่ต้อง CloudWatch ส่งอีเวนต์การเปลี่ยนสถานะของ alarm ไปยัง EventBridge เองอยู่แล้ว ไม่ว่า alarm จะมีแอ็กชันหรือไม่ คุณปล่อยรายการแอ็กชันของ alarm ให้ว่างได้
CloudWatch alarm ทะลุโหมดห้ามรบกวนไหม
เฉพาะเมื่อมาถึงในรูปการแจ้งเตือนแบบสายเรียกเข้าเท่านั้น ช่อง Echobell ประเภทโทรเข้าทำงานเหมือนสายเรียกเข้า ซึ่งโหมดโฟกัสและห้ามรบกวนของ iOS ยอมให้ผ่าน ส่วน SMS หรือพุชธรรมดาไม่ผ่าน
ทำไมไม่สมัคร URL เว็บฮุกเข้ากับ SNS ไปเลย
SNS ส่ง text/plain โดยมี alarm ถูกแปลงเป็นสตริงอยู่ใน Message เทมเพลตจึงอ่านทีละฟิลด์ไม่ได้ และซองก็ยาวพอที่จะถูกตัด นอกจากนี้ SNS ยังส่งการยืนยันการสมัครมาก่อน ซึ่งจะมาถึงเป็นการแจ้งเตือน
ใช้ AWS แล้วมีค่าใช้จ่ายไหม
อีเวนต์การเปลี่ยนสถานะของ alarm เข้าสู่ default event bus โดยไม่คิดค่าใช้จ่าย ส่วนการเรียก API destination คิดเป็นรายคำขอ ที่ปริมาณของชุด alarm ที่ทำงานปกติ ถือว่าน้อยมาก แต่ควรตรวจราคา EventBridge ปัจจุบันของรีเจียนคุณ
โทรหาคนละคนสำหรับ alarm ต่างกันได้ไหม
ได้ สร้างหนึ่งช่องต่อกลุ่มผู้รับ หนึ่งกฎต่อช่อง แล้วให้แต่ละคนสมัครรับด้วยประเภทการแจ้งเตือนที่ต้องการ เนื่องจากไม่มีการตอบรับ ทุกคนที่สมัครรับแบบ "โทรเข้า" จะได้รับสายทั้งหมด
แล้ว alarm ในหลายรีเจียนหรือหลายบัญชีล่ะ
กฎเป็นแบบรายรีเจียน จึงสร้างกฎในทุกรีเจียนที่ใช้ (นิยาม API destination เดียวกันต้องทำซ้ำในแต่ละรีเจียน) สำหรับหลายบัญชี ให้ส่งอีเวนต์ไปยัง bus กลางในบัญชีหนึ่งแล้ววางกฎไว้ที่นั่น
สรุป
เส้นทางนี้มีห้าส่วน: ช่องแบบโทรเข้า, connection และ API destination ที่ชี้ไปที่ช่องนั้น, กฎที่จับเฉพาะ alarm ที่คุ้มค่าต่อการปลุกใครสักคน, input transformer ที่ทำให้อีเวนต์แบน และการทดสอบด้วย set-alarm-state ก่อนจะพึ่งพาอะไรทั้งหมดนี้ ที่เหลือในหน้านี้ล้วนว่าด้วยการรักษาให้มันแคบพอ เพื่อให้อีกหนึ่งเดือนข้างหน้าเสียงเรียกเข้ายังมีความหมายอยู่
ดาวน์โหลด Echobell สำหรับ iPhone หรือ รับบน Google Play แล้วลองทดสอบด้วย set-alarm-state