02-telemetry

Example of the component nguyenduchoai/innoedge v0.1.4
<a id="top"></a>
# 02 — Telemetry: Tiền & Cảnh báo (Money & Alerts)

> 🇻🇳 **Tài liệu Tiếng Việt** (toàn bộ nội dung bên dưới) | [🇬🇧 English Documentation](#english)

Gửi giao dịch tiền và cảnh báo sự cố lên cloud, an toàn trước mất mạng/mất điện.

## Phần cứng
Chỉ cần bo devkit — dùng nút **BOOT (GPIO0)** có sẵn.

| Thao tác | Ý nghĩa |
|---|---|
| Bấm nhanh BOOT | khách bỏ 1 xu → `innoedge_publish_payment()` |
| Giữ BOOT > 2s | máy kẹt xu → `innoedge_alert(..., true)` |
| Thả ra | hết kẹt → `innoedge_alert(..., false)` |

## Build
```bash
idf.py set-target esp32s3 && idf.py flash monitor
```

## Bài test quan trọng nhất: rớt mạng không mất tiền

1. Máy online, bấm BOOT → log `cloud đã ghi: ...`, `tồn 0`.
2. **Tắt WiFi router** (hoặc `idf.py monitor` rồi rút mạng).
3. Bấm BOOT 5 lần → `tồn 1,2,3,4,5` — không có `cloud đã ghi`.
4. **Bật lại WiFi**.
5. Trong ~3s: 5 dòng `cloud đã ghi` chạy về, `tồn` về 0.
6. Rút điện giữa bước 3 rồi cắm lại → hàng đợi vẫn còn nguyên (nằm trong NVS).

## 4 loại tiền SDK hỗ trợ
```c
innoedge_publish_payment(INNOEDGE_PAY_COIN,     3, 0);      // khách bỏ 3 xu
innoedge_publish_payment(INNOEDGE_PAY_CASH,     0, 20000);  // bill 20.000đ
innoedge_publish_payment(INNOEDGE_PAY_TICKET,  25, 0);      // hủy 25 vé thưởng
innoedge_publish_payment(INNOEDGE_PAY_COIN_OUT, 10, 0);     // trả khách 10 xu
```
`TICKET` và `COIN_OUT` **không tính doanh thu** — chúng để đối soát.

## Quy tắc cảnh báo
- `code` là định danh máy-đọc (`coin_jam`, `coin_empty`, `paper_empty`, `no_water`…).
- Cloud gom theo `(máy, code)`: 1 cảnh báo active mỗi code; gọi lặp chỉ tăng `count`.
- `active=false` = resolve. **Luôn nhớ clear** — không thì app đối tác đỏ mãi.
- Gọi khi offline vẫn an toàn (trả lỗi, không crash).

## Điều SDK làm mà bạn không thấy
| Việc | Chi tiết |
|---|---|
| Cấp `seq` đơn điệu | lưu NVS, dùng để cloud dedupe |
| Ghi NVS trước khi gửi | mất điện không mất tiền |
| Gửi lại tới khi có ack | mỗi 3s + ngay khi ack phần tử trước |
| Hàng đợi gần đầy | tự phát alert `payment_queue_backlog_high` (80% cap) |
| Hàng đợi tràn | tự phát alert `payment_queue_overflow_drop` **critical** — không nuốt tiền trong im lặng |

## Troubleshooting
| Triệu chứng | Nguyên nhân |
|---|---|
| Không thấy `cloud đã ghi` dù online | Máy chưa được gán đối tác → cloud không ack (đúng thiết kế, tiền giữ trong hàng đợi) |
| `tồn` tăng mãi không giảm | Kiểm tra `assigned` ở example 01 trước |
| Alert không hiện trên app | `code` gửi rồi nhưng chưa clear cái cũ — mỗi code chỉ 1 alert active |

---

<a id="english"></a>
## 🇬🇧 English Documentation

> [🇻🇳 Quay lại Tiếng Việt](#top)

Dispatch financial transactions and hardware alerts to the cloud with crash-safe NVS persistence against network drops and sudden power loss.

## Hardware Requirements
Only a devkit board — uses the onboard **BOOT button (GPIO0)**.

| Action | Meaning |
|---|---|
| Quick press BOOT | Customer inserts 1 coin → `innoedge_publish_payment()` |
| Hold BOOT > 2s | Coin mechanism jammed → `innoedge_alert(..., true)` |
| Release BOOT | Coin jam cleared → `innoedge_alert(..., false)` |

## Build & Flash
```bash
idf.py set-target esp32s3 && idf.py flash monitor
```

## The Crucial Test: Zero Lost Money on Network Drop

1. When the device is online, press BOOT → Log shows `cloud acknowledged payment`, `queue_depth=0`.
2. **Turn off your WiFi router** (or unplug network cable).
3. Press BOOT 5 times → Log shows `queue_depth=1,2,3,4,5` — no cloud acknowledgement.
4. **Turn WiFi back on**.
5. Within ~3s: 5 acknowledgment logs stream back from the cloud, and `queue_depth` returns to 0.
6. Unplug the USB cable during Step 3 and plug back in → The payment queue remains completely intact inside NVS flash memory.

## 4 Supported Payment Kinds
```c
innoedge_publish_payment(INNOEDGE_PAY_COIN,     3, 0);      // Customer inserted 3 coins
innoedge_publish_payment(INNOEDGE_PAY_CASH,     0, 20000);  // Bill acceptor: 20,000 VND
innoedge_publish_payment(INNOEDGE_PAY_TICKET,  25, 0);      // Redeem 25 prize tickets
innoedge_publish_payment(INNOEDGE_PAY_COIN_OUT, 10, 0);     // Hopper dispensed 10 coins
```
*Note:* `TICKET` and `COIN_OUT` do not increment revenue — they are used for financial audits and hopper balance tracking.

## Hardware Alert Rules
- `code` is a machine-readable identifier (`coin_jam`, `coin_empty`, `paper_empty`, `no_water`, etc.).
- The cloud deduplicates on `(device_id, code)`: exactly 1 active alert per code; repeated triggers simply increment the counter.
- `active=false` marks the alert as resolved. **Always remember to clear alerts** once the hardware condition returns to normal.
- Safe to call while offline (records state safely without crashing).

## Under the Hood: What the SDK Handles for You
| Feature | Details |
|---|---|
| Monotonic `seq` counter | Persisted to NVS, used by cloud for idempotency |
| NVS write before transmission | Zero lost money on sudden power failure |
| Automatic retry until ACK | Retries every 3s + immediately upon previous ACK |
| Queue near capacity | Automatically raises `payment_queue_backlog_high` alert (80% threshold) |
| Queue overflow safety | Automatically raises `payment_queue_overflow_drop` **critical** alert — never drops money silently |

## Troubleshooting
| Symptom | Cause & Solution |
|---|---|
| No cloud acknowledgment while online | Device not yet assigned to partner — cloud rejects unassigned payments (intended design; money stays safely in queue). |
| Queue depth grows and never decreases | Check device assignment status from Example 01. |
| Alert still shows on app after hardware fix | Alert was triggered with `active=true` but not cleared with `active=false`. |

To create a project from this example, run:

idf.py create-project-from-example "nguyenduchoai/innoedge=0.1.4:02-telemetry"

or download archive (~7.34 KB)