Skip to content

Raise an alarm

IoT Coregg-edge/telemetry/+
→
CloudWatchChipTempC-<thing> · alarm
→
SNSemail · Lambda next
Threshold is each zone’s current DynamoDB 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).

Terminal window
set -a && source config/walkthrough.env && set +a
export GG_EDGE_ALLOW_AWS=1
AWS_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-2

Set ALERT_EMAIL in config/walkthrough.env to an inbox you can open before the SNS subscribe step.

Terminal window
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)
Terminal window
sed "s|IOT_RULE_ROLE_ARN|${IOT_RULE_ROLE_ARN}|g" \
artifacts/iot-rules/telemetry-to-cloudwatch.json > /tmp/rule-telemetry-cw.json
aws iot create-topic-rule --rule-name "${RULE_PREFIX}_telemetry_cw" \
--topic-rule-payload file:///tmp/rule-telemetry-cw.json
(no output)

Wait about 3 minutes. get-metric-statistics returns datapoints before a new metric name shows up in list-metrics.

Terminal window
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 text
2026-10-10T11:50:00+13:00 29.9 29.9
2026-10-10T11:51:00+13:00 29.9 29.9
2026-10-10T11:52:00+13:00 29.9 29.9
Terminal window
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-alarms
Terminal window
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:

Terminal window
aws sns list-subscriptions-by-topic --topic-arn "$ALARM_TOPIC_ARN" \
--query "Subscriptions[].[Protocol,Endpoint,SubscriptionArn]" --output text
email you@example.com arn:aws:sns:ap-southeast-2:123456789012:gg-edge-wt-dev-zone-alarms:…

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.

Terminal window
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"
done
gg-edge-wt-dev-esp32-1 baseline=29.9 threshold=31.9
gg-edge-wt-dev-esp32-2 baseline=27.5 threshold=29.5
Terminal window
aws cloudwatch describe-alarms --alarm-name-prefix "${PROJECT_NAME}-${ENVIRONMENT}-hot-" \
--query "MetricAlarms[].[AlarmName,StateValue,Threshold]" --output text
gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-1 OK 31.9
gg-edge-wt-dev-hot-gg-edge-wt-dev-esp32-2 OK 29.5

A new alarm starts as INSUFFICIENT_DATA and turns OK after its first period.

set-alarm-state forces a transition, which sends a notification. The alarm returns to its real state at the next evaluation.

Terminal window
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) region
has 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) region
has entered the OK state, because "Threshold Crossed: 1 out of the last 1
datapoints [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-1
Terminal window
aws 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 text
2026-10-10T12:01:50+13:00 Alarm updated from OK to ALARM
2026-10-10T12:02:37+13:00 Alarm updated from ALARM to OK

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=0

Next: Cloud commands.