Experiment record

SwitchBot CO2 alerts to a family LINE group with Google Apps Script

A five-minute SwitchBot CO2 collector was extended with persistence, hysteresis, and LINE group push notifications. An intentionally induced high reading produced a real family-group warning at 2812 ppm; 30-minute repeat warnings and the silent reset path remain unverified.

Conclusion

An existing SwitchBot home-environment collector was extended with an automated ventilation alert path to a private family LINE group.

The production data path is:

SwitchBot MeterPro(CO2)
SwitchBot OpenAPI v1.1
Google Apps Script
5-minute measurement trigger
private Google Sheets measurement log
CO2 alert state logic
LINE Messaging API push
private family group

The initial end-to-end alert case was functionally verified. During a deliberate functional test, the operator exhaled near the CO2 sensor to raise its reading. At 16:38 JST on 2026-08-16, the target LINE group received a ventilation warning showing 2812 ppm and a displayed high-CO2 continuation time of 4 minutes.

Two behaviors are deliberately still marked unverified: the repeated warning after 30 minutes of sustained/re-established high CO2, and the silent return to normal after CO2 remains below the reset threshold for 10 minutes.

1. Objective

The goal was not to create another dashboard. The requirement was to notify household members only when action is useful, while avoiding a LINE message on every five-minute sample above the threshold.

The existing environmental collector already obtained CO2 measurements on a nominal five-minute schedule. Reusing that execution path avoids a second polling loop and keeps the alert decision tied to the same observation stream stored privately in Google Sheets.

2. Alert design

The configured design uses persistence plus hysteresis.

NORMAL
  │ CO2 > 1000 ppm on two consecutive scheduled samples
ALERT
  ├─ CO2 > 1000 ppm continuously again long enough,
  │  and ≥30 min since the previous notification
  │       → repeated warning
  ├─ 900–1000 ppm
  │       → no notification; ALERT is retained
  └─ CO2 < 900 ppm for ≥10 min
          → return to NORMAL silently

The 1000/900 ppm separation is intentional hysteresis. It prevents repeated state changes when the reading oscillates around one threshold.

A missing CO2 value or API error must not be interpreted as proof that the high or low condition continued through the missing interval.

3. Notification behavior

The first warning and repeated warnings use different message text. The public record preserves the behavior, not the private destination or exact account configuration.

The initial warning identifies the living-space CO2 condition, shows the current ppm value and continuation time, and asks for ventilation. A repeated warning is designed to state that the high-CO2 condition has continued for at least 30 minutes and again show the current reading and duration.

Clear-state messages are intentionally suppressed. The system resets its internal state after the low-CO2 condition is confirmed, but does not send a “recovered” LINE message.

4. LINE group destination setup

LINE Messaging API push messages can be sent to a group once its group ID is known and the LINE Official Account is present in that group.

For this implementation, the group ID was captured once through a webhook event and then stored privately in Google Apps Script Script Properties together with the channel access token. After that, normal CO2 alerts use push messaging only; a continuously enabled webhook is not required for the alert path.

The following values are deliberately not published:

5. Failure: direct Apps Script webhook path

The first attempt used a Google Apps Script Web App as the temporary LINE webhook receiver.

During setup, LINE webhook verification first encountered HTTP 404. After the endpoint and deployment were corrected, the tested response path returned HTTP 302 rather than the direct successful response expected by the LINE verifier.

This path was therefore abandoned for the one-time group-ID capture task. The failure is retained because it is useful implementation data rather than being hidden from the final record.

6. Recovery: temporary Cloudflare Worker

A minimal Cloudflare Worker was created as the temporary webhook receiver.

Its job was limited to:

  1. receive the LINE webhook request,
  2. validate the x-line-signature using HMAC-SHA256 and the private channel secret,
  3. expose the group ID in controlled logs for one-time capture,
  4. return HTTP 200 directly.

LINE’s webhook verification succeeded with this receiver. A message was then sent in the private group, the resulting group ID was captured, and that ID was stored in Google Apps Script Script Properties.

After successful capture, the Cloudflare Worker was deleted and LINE webhook delivery was turned off. The production CO2 notification path therefore has no Cloudflare dependency.

7. Observed functional test

EXECUTED

The operator deliberately exhaled near the installed CO2 sensor to raise the measured concentration for a short functional test.

OBSERVED

A LINE ventilation alert was received in the intended private family group at 16:38 JST.

The message displayed:

The private screenshot also contains family-group information and is therefore retained privately rather than embedded in this public article.

VERIFIED

This observation verifies the initial end-to-end path:

CO2 measurement
→ automated threshold/state processing
→ LINE Messaging API push
→ intended private group

It does not yet verify every branch of the state machine.

8. Not yet verified

The following remain open tests:

Until those observations exist, they are implementation targets rather than fully verified runtime behavior.

9. Privacy and publication boundary

This experiment concerns a private residence and a family communication group. The public record therefore excludes raw five-minute household telemetry, exact residence-identifying information, personal room names, device IDs, spreadsheet IDs, LINE identifiers, credentials, account information, webhook URLs, and the actual group screenshot.

Only the reusable architecture, threshold/state logic, troubleshooting path, and anonymized functional observation are published.

10. Reproduction outline

A comparable system can be reproduced without any of the private values used here:

  1. Collect CO2 from an owned sensor on a stable schedule.
  2. Preserve the raw observation before running notification logic.
  3. Store notification state separately from measurement data.
  4. Require persistence before the first alert.
  5. Use a lower clear threshold than the alert threshold to provide hysteresis.
  6. Rate-limit repeated warnings using elapsed time rather than trigger-count assumptions.
  7. Store LINE credentials and the destination identifier in a secret/configuration store, not source code or the spreadsheet.
  8. Test the initial alert, repeat path, clear path, missing-data behavior, and re-alert behavior independently.

The underlying five-minute household environmental collection system is documented separately as SWITCHBOT-HOME-ENV-001.