Raise an alarm
tempC + 2 °C. Next page attaches Lambda to the same topic for blue RGB.The third consumer of gg-edge/telemetry/+ is CloudWatch. An
IoT rule
AWS IoT rule — SQL over an MQTT topic filter plus actions (S3, DynamoDB, CloudWatch, …). This is how IoT Core hands bridged Greengrass data to other AWS services. publishes tempC as the metric
GgEdge/Greenhouse › ChipTempC-<thing>. A CloudWatch alarm on each zone
notifies an SNS topic. You get email on this page, and the same topic triggers
a Lambda on the next page.
The rule names the metric per zone with ${topic(3)}. The cloudwatchMetric
action does not set dimensions, so the zone has to be part of the metric name
(CloudWatch metric action).
1. Session variables
Section titled “1. Session variables”set -a && source config/walkthrough.env && set +aexport GG_EDGE_ALLOW_AWS=1AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)RULE_PREFIX=$(echo "${PROJECT_NAME}_${ENVIRONMENT}" | tr '-' '_')IOT_RULE_ROLE="${PROJECT_NAME}-${ENVIRONMENT}-iot-rules"IOT_RULE_ROLE_ARN=$(aws iam get-role --role-name "$IOT_RULE_ROLE" --query Role.Arn --output text)ZONE_TABLE="${ZONE_TABLE:-${PROJECT_NAME}-${ENVIRONMENT}-zone-state}"ALARM_TOPIC="${ALARM_TOPIC:-${PROJECT_NAME}-${ENVIRONMENT}-zone-alarms}"ZONES="$CLIENT_THING_NAME ${CLIENT_THING_NAME_2:-}"echo "$ZONES"gg-edge-wt-dev-esp32-1 gg-edge-wt-dev-esp32-2Set ALERT_EMAIL in config/walkthrough.env to an inbox you can open before
the SNS subscribe step.
2. Telemetry → CloudWatch metric
Section titled “2. Telemetry → CloudWatch metric”Allow PutMetricData in one namespace
Section titled “Allow PutMetricData in one namespace”aws iam put-role-policy --role-name "$IOT_RULE_ROLE" \ --policy-name iot-rule-cloudwatch \ --policy-document file://artifacts/policies/iot-rule-cloudwatch.json(no output)Create the rule
Section titled “Create the rule”sed "s|IOT_RULE_ROLE_ARN|${IOT_RULE_ROLE_ARN}|g" \ artifacts/iot-rules/telemetry-to-cloudwatch.json > /tmp/rule-telemetry-cw.jsonaws iot create-topic-rule --rule-name "${RULE_PREFIX}_telemetry_cw" \ --topic-rule-payload file:///tmp/rule-telemetry-cw.json(no output)See datapoints
Section titled “See datapoints”Wait about 3 minutes. get-metric-statistics returns datapoints before a new
metric name shows up in list-metrics.
aws cloudwatch get-metric-statistics --namespace GgEdge/Greenhouse \ --metric-name "ChipTempC-${CLIENT_THING_NAME}" \ --start-time "$(date -u -d '-10 min' +%Y-%m-%dT%H:%M:%SZ)" \ --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --period 60 --statistics Average Maximum \ --query "sort_by(Datapoints,&Timestamp)[].[Timestamp,Average,Maximum]" --output text2026-10-10T11:50:00+13:00 29.9 29.92026-10-10T11:51:00+13:00 29.9 29.92026-10-10T11:52:00+13:00 29.9 29.93. SNS topic and email
Section titled “3. SNS topic and email”Create the topic
Section titled “Create the topic”ALARM_TOPIC_ARN=$(aws sns create-topic --name "$ALARM_TOPIC" --query TopicArn --output text)echo "$ALARM_TOPIC_ARN"arn:aws:sns:ap-southeast-2:123456789012:gg-edge-wt-dev-zone-alarmsSubscribe your inbox
Section titled “Subscribe your inbox”aws sns subscribe --topic-arn "$ALARM_TOPIC_ARN" \ --protocol email --notification-endpoint "$ALERT_EMAIL"{ "SubscriptionArn": "pending confirmation"}Open the AWS Notification - Subscription Confirmation email and click Confirm subscription. Then check:
aws sns list-subscriptions-by-topic --topic-arn "$ALARM_TOPIC_ARN" \ --query "Subscriptions[].[Protocol,Endpoint,SubscriptionArn]" --output textemail you@example.com arn:aws:sns:ap-southeast-2:123456789012:gg-edge-wt-dev-zone-alarms:…4. One alarm per zone
Section titled “4. One alarm per zone”The chip sensor runs a few degrees above room temperature, and each board has its own offset. The threshold is each zone’s current reading from DynamoDB plus 2 °C.
for t in $ZONES; do BASE=$(aws dynamodb get-item --table-name "$ZONE_TABLE" \ --key "{\"thing\":{\"S\":\"$t\"},\"kind\":{\"S\":\"telemetry\"}}" \ --query Item.tempC.N --output text) THRESHOLD=$(awk -v b="$BASE" 'BEGIN{printf "%.1f", b + 2}') aws cloudwatch put-metric-alarm --alarm-name "${PROJECT_NAME}-${ENVIRONMENT}-hot-${t}" \ --alarm-description "Zone $t chip temperature > ${THRESHOLD} C" \ --namespace GgEdge/Greenhouse --metric-name "ChipTempC-$t" \ --statistic Maximum --period 60 --evaluation-periods 1 --datapoints-to-alarm 1 \ --threshold "$THRESHOLD" --comparison-operator GreaterThanThreshold \ --treat-missing-data notBreaching \ --alarm-actions "$ALARM_TOPIC_ARN" --ok-actions "$ALARM_TOPIC_ARN" echo "$t baseline=$BASE threshold=$THRESHOLD"donegg-edge-wt-dev-esp32-1 baseline=29.9 threshold=31.9gg-edge-wt-dev-esp32-2 baseline=27.5 threshold=29.5Check state
Section titled “Check state”aws cloudwatch describe-alarms --alarm-name-prefix "${PROJECT_NAME}-${ENVIRONMENT}-hot-" \ --query "MetricAlarms[].[AlarmName,StateValue,Threshold]" --output textgg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-1 OK 31.9gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-2 OK 29.5A new alarm starts as INSUFFICIENT_DATA and turns OK after its first
period.
5. Trip it
Section titled “5. Trip it”Wiring test without heat
Section titled “Wiring test without heat”set-alarm-state forces a transition, which sends a notification. The alarm
returns to its real state at the next evaluation.
aws cloudwatch set-alarm-state \ --alarm-name "${PROJECT_NAME}-${ENVIRONMENT}-hot-${CLIENT_THING_NAME}" \ --state-value ALARM --state-reason "wiring test"(no output)If the SNS email subscription is confirmed, an ALARM email arrives within a minute, followed by an OK email when the metric is back under threshold.
Sample ALARM mail (account ID and inbox masked):
You are receiving this email because your Amazon CloudWatch Alarm"gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-1" in the Asia Pacific (Sydney) regionhas entered the ALARM state, because "wiring test" at"Friday 09 October, 2026 23:01:50 UTC".
Alarm Details:- Name: gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-1- Description: Zone gg-edge-wt-dev-esp32-1 chip temperature > 31.9 C- State Change: OK -> ALARM- Reason for State Change: wiring test- Timestamp: Friday 09 October, 2026 23:01:50 UTC- AWS Account: 123456789012
Threshold:- GreaterThanThreshold 31.9 for at least 1 of the last 1 period(s) of 60 seconds.
Monitored Metric:- MetricNamespace: GgEdge/Greenhouse- MetricName: ChipTempC-gg-edge-wt-dev-esp32-1- Period: 60 seconds- Statistic: Maximum
State Change Actions:- OK: [arn:aws:sns:ap-southeast-2:123456789012:gg-edge-wt-dev-zone-alarms]- ALARM: [arn:aws:sns:ap-southeast-2:123456789012:gg-edge-wt-dev-zone-alarms]Sample OK mail after the metric re-evaluates under threshold:
You are receiving this email because your Amazon CloudWatch Alarm"gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-1" in the Asia Pacific (Sydney) regionhas entered the OK state, because "Threshold Crossed: 1 out of the last 1datapoints [29.9 (09/10/26 23:01:00)] was not greater than the threshold (31.9)(minimum 1 datapoint for ALARM -> OK transition)." at"Friday 09 October, 2026 23:02:37 UTC".
Alarm Details:- Name: gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-1- State Change: ALARM -> OK- Timestamp: Friday 09 October, 2026 23:02:37 UTC- AWS Account: 123456789012
Monitored Metric:- MetricNamespace: GgEdge/Greenhouse- MetricName: ChipTempC-gg-edge-wt-dev-esp32-1aws cloudwatch describe-alarm-history \ --alarm-name "${PROJECT_NAME}-${ENVIRONMENT}-hot-${CLIENT_THING_NAME}" \ --history-item-type StateUpdate --max-items 3 \ --query "AlarmHistoryItems[].[Timestamp,HistorySummary]" --output text2026-10-10T12:01:50+13:00 Alarm updated from OK to ALARM2026-10-10T12:02:37+13:00 Alarm updated from ALARM to OKReal heat
Section titled “Real heat”Hold your thumb on the metal can of the esp32-1 module for about 2 minutes,
or point a hair dryer at it from a distance. Expect 1–3 minutes from heat to
alarm (10 s sample + 1-minute CloudWatch period). Edge inference later reacts
on the core in about 20 s.
I (2511023) gg-edge: telemetry {"thing":"gg-edge-wt-dev-esp32-1","tempC":31.30,"rssi":-30,"uptimeS":2511,"rgb":"off"} msg_id=0Next: Cloud commands.