Sự kiện AI & cảnh báo — đếm người / xe, xâm nhập vùng cấm, nhận diện khuôn mặt
Ngoài đọc biển số, camera TingPush có khung sự kiện AI: camera phân tích hình, phát hiện sự kiện, máy chủ TingPush lưu lại và báo ngay về điện thoại qua thư viện thông báo của TingPush — thông báo đẩy, hoặc cuộc gọi (đổ chuông toàn màn hình như cuộc gọi đến, kể cả khi máy khóa) khi có người xâm nhập.
| Tính năng | Camera làm gì | Báo về điện thoại (mặc định) |
|---|---|---|
| Xâm nhập vùng cấm | Người (hoặc xe) có chân nằm trong vùng đa giác đã vẽ ≥ N giây | Gọi điện (+ thông báo khi không dùng gọi) |
| Nhận diện khuôn mặt | So khuôn mặt với thư viện người quen; báo người quen / người lạ | Thông báo đẩy |
| Học khuôn mặt (người hay gặp) | Camera trong nhà tự ghi nhớ người lạ hay xuất hiện, đếm số ngày; thấy liên tục N ngày (mặc định 7) thì tự thêm vào người nhà — mục 1 | Báo khi tự thêm người nhà |
| Chấm công | Dùng chung thư viện khuôn mặt (nhân viên); ghi giờ đến / về, gửi như biển số — xem Chấm công bằng khuôn mặt — camera TingPush làm máy chấm công | Không báo (xem trang Chấm công) |
| Đếm người / xe | Đếm mỗi lượt đi qua vạch theo chiều vào / ra (vào rồi quay ra = 1 vào + 1 ra), gửi số đếm mỗi chu kỳ | Không báo; bật "Báo khi nhiều lượt vào" theo ngưỡng |
| Số đang ở bên trong | Camera tự cộng vào − trừ ra qua mọi vạch, về 0 mỗi ngày lúc giờ đặt lại, giữ qua khởi động lại | Quá đông: thông báo ngay khi vượt ngưỡng (tùy chọn gọi điện) |
| Đọc biển số (có sẵn) | Như cũ | Thông báo khi gặp biển trong danh sách theo dõi (tự bật) |
Model AI: khung đã chạy đầy đủ (theo dõi đối tượng, vạch, vùng, khuôn mặt, lịch, cảnh báo). Phần model nhận dạng người / xe và khuôn mặt nạp sau (mục 7). Chưa có model vẫn thử cảnh báo được bằng nút Thử trên app (mục 8).
Camera ──(WebSocket, tức thì, không ảnh)──► Máy chủ TingPush ──► TingPush (POST /notifications) ──► APNs / FCM ──► App
└─(HTTP /api/device/events, kèm ảnh, có hàng đợi khi mất mạng)──┘ │
└─► lưu sự kiện, số đếm (web, app, API /api/v1)
1. Dùng trên app TingPush Camera
- Camera → chọn camera → ⚙ Cài đặt camera → Tính năng AI & cảnh báo.
- Bật tính năng, rồi:
- Xâm nhập: chạm ô xem trước để vẽ vùng cấm trên hình trực tiếp (kéo các điểm tròn, Thêm điểm, tối đa 4 vùng × 12 điểm), chọn Người / Xe, thời gian ở trong vùng để báo, Không báo lặp trong (giây), giờ canh + ngày.
- Đếm: vẽ vạch ngang lối đi; mũi tên chỉ hướng vào (Đảo chiều vào / ra để đổi). Chọn chu kỳ gửi số đếm. Xem biểu đồ ở Sự kiện → biểu tượng 📈 Thống kê đếm (hôm nay theo giờ, 7 / 30 ngày theo ngày, theo từng vạch).
- Số đang ở bên trong (vào − ra): xem số hiện tại, Sửa (về 0 hoặc nhập số thực tế, VD đầu ca), Giờ đặt lại về 0 mỗi ngày, Báo khi bên trong từ N (0 = tắt), Không báo lại trong (giây — số dao động quanh ngưỡng không báo liên tục). Nhiều cửa: vẽ mỗi cửa một vạch, mũi tên đều chỉ vào trong, camera cộng chung. Cần mọi lối ra vào đều có vạch trong tầm camera thì số bên trong mới đúng.
- Khuôn mặt: thêm người quen ở Thư viện khuôn mặt (ảnh chân dung rõ mặt, chọn camera nhận diện), đặt độ giống tối thiểu, Báo cả người lạ, vùng nhận diện (tùy chọn).
- Chọn cách báo cho từng tính năng: Thông báo đẩy, Gọi điện. Mỗi người (chủ và người được chia sẻ) tự chọn cho riêng mình; người được chia sẻ chỉ chỉnh được cách báo, không bật/tắt được tính năng.
- Bấm Lưu (cấu hình lưu trên camera). Bấm Thử cảnh báo xâm nhập để kiểm tra điện thoại đổ chuông.
Tab Sự kiện liệt kê mọi sự kiện (lọc theo loại / camera), cập nhật ngay khi xảy ra; chạm để xem ảnh toàn cảnh, ảnh cắt đối tượng, Xem trực tiếp camera, Xem lại thẻ nhớ. Web: https://webrtc.tingpush.com/events.
Cuộc gọi cảnh báo
- Mọi người được bật Gọi điện cùng đổ chuông. Người đầu tiên bấm "Xem ngay" → app mở hình trực tiếp camera, máy chủ báo các máy khác tắt chuông (kèm thông báo "Đã có người nghe").
- Không ai nghe trong 45 giây → tắt chuông, gửi thông báo "Cảnh báo nhỡ".
- Android 14+: lần đầu vào Tài khoản → Cảnh báo AI → Cho phép hiện cuộc gọi khi khóa máy. Máy Xiaomi / Oppo / Vivo / Realme / Huawei: bật Tự khởi động và tắt Tối ưu pin cho app (như Zalo) để chuông ổn định.
Học khuôn mặt — người hay gặp (camera trong nhà)
Không cần chụp ảnh từng người nhà: bật Học khuôn mặt (Tính năng AI → Nhận diện khuôn mặt; web: menu Người hay gặp), camera tự làm:
- Mỗi khuôn mặt lạ (chưa có trong thư viện) nhìn đủ rõ được gom vào một nhóm theo đặc trưng khuôn mặt. Mỗi nhóm ghi: số ngày đã thấy, chuỗi ngày liên tục, số lượt (cách nhau ≥ 1 phút), khung giờ hay gặp, ảnh mặt rõ nhất.
- Nhóm thấy liên tục N ngày (cài được 1–60, mặc định 7; đặt 0 = không tự thêm) → camera tự thêm vào người nhà (thư viện khuôn mặt, tên tạm "Người nhà mới XXXX"), máy chủ lưu ảnh và báo cho chủ camera (luôn báo, kể cả khi đã tắt thông báo khuôn mặt) — không phải người nhà thì xóa ngay ở trang Nhân viên / người nhà. Đổi tên ở đó là camera nhận tên mới ngay.
- Chưa đủ ngày: chủ nhà xem danh sách Người hay gặp (app: Tính năng AI → Người hay gặp, hoặc Nhân viên & khuôn mặt
→ ⋮; web
/face-learn; Windows: Nhân viên → Người hay gặp…): Là người nhà (đặt tên → vào thư viện ngay), Gộp (2 ô là cùng một người — VD ảnh ban ngày / đêm hồng ngoại), Xóa, Xóa tất cả. - Sự kiện người lạ kèm số ngày đã thấy: "Phát hiện người lạ (đã thấy 3 ngày)".
- Nhóm chưa xác nhận không gặp quá N ngày (mặc định 30) thì tự xóa; nhóm chỉ thấy 1 lượt bị xóa sau 3 ngày (người đi ngang); tối đa 300 nhóm. Camera tự gộp định kỳ các nhóm quá giống nhau.
Lưu ý:
- Dữ liệu nhóm (đặc trưng + ảnh mặt) chỉ nằm trên camera (
/userdata/lpr/face_learn.db,face_learn/<id>.jpg); chỉ khi thành người nhà mới gửi ảnh lên máy chủ. Tắt học khuôn mặt thì danh sách cũ vẫn giữ tới khi bấm Xóa tất cả. - Liên tục nghĩa là không sót ngày nào: đi vắng 1 ngày là đếm lại. Người giúp việc / bảo vệ đến hằng ngày cũng sẽ thành "người nhà" — đổi tên cho đúng hoặc xóa.
- Rủi ro: người lạ cố tình xuất hiện đủ N ngày liên tục cũng được tự thêm. Vì vậy camera luôn báo khi tự thêm người; nhà cần an ninh cao đặt 0 ngày (chỉ gợi ý, chủ nhà tự xác nhận).
- Gom nhóm dùng ngưỡng chặt hơn ngưỡng nhận diện (thà tách 1 người thành 2 ô để gộp tay còn hơn gộp nhầm 2 người).
- Thông báo cho người trong ảnh nếu camera đặt ở nơi có người ngoài (khách, người giúp việc) — dữ liệu khuôn mặt là dữ liệu cá nhân nhạy cảm.
2. Cấu hình máy chủ (quản trị)
camera_server/appsettings.json:
"TingPush": {
"ServerUrl": "https://tingpush.com",
"AppId": "15712fca-623e-410b-be30-f3b278a12eb9",
"ApiKey": "",
"ExternalIdPrefix": "u",
"CallTimeoutS": 45
}
API Key psk_… là bí mật — không ghi vào appsettings.json, không đưa lên git. Đặt bằng biến môi trường của dịch vụ:
# systemd: /etc/systemd/system/cameraserver.service → [Service]
Environment=TingPush__ApiKey=psk_xxxxxxxxxxxxxxxx
# Docker: -e TingPush__ApiKey=psk_xxx Phát triển: dotnet user-secrets set "TingPush:ApiKey" "psk_xxx"
Chưa đặt ApiKey thì máy chủ vẫn lưu sự kiện, chỉ ghi log thay cho gửi thông báo. Lộ khóa → tạo khóa mới trên trang quản trị TingPush và xóa khóa cũ.
Người nhận: app đăng nhập SDK bằng external_id = ExternalIdPrefix + mã tài khoản (VD u12), máy chủ trả qua
GET /api/me/push. Không cần lưu token thiết bị trên máy chủ camera.
Gói dịch vụ (web → Quản trị → Gói dịch vụ): Sự kiện AI (lưu + thông báo), Cảnh báo bằng cuộc gọi, Sự kiện AI / tháng (0 = không giới hạn; vượt thì ngừng nhận tới tháng sau), Số khuôn mặt tối đa. Số thông báo / cuộc gọi đã gửi hiện trên trang Sự kiện AI và bảng sử dụng.
Trên trang quản trị TingPush (tingpush.com)
- Android: tải lên service account JSON của project Firebase mà app dùng.
- iOS: tải lên key
.p8của Apple (APNs), Team ID, Key ID, bundlecom.tingpush.camera. Cuộc gọi trên iOS đi qua VoIP push (PushKit) → CallKit.
3. Build app có thông báo đẩy (lập trình viên app)
App dùng gói Flutter tingpush (+ firebase_core). Cần cấu hình Firebase cho Android / iOS — chọn một cách:
- File cấu hình gốc: đặt
android/app/google-services.json(và plugin Gradlecom.google.gms.google-services),ios/Runner/GoogleService-Info.plist; hoặc - dart-define (không cần file):
flutter build apk --release \
--dart-define=FIREBASE_API_KEY=AIza... \
--dart-define=FIREBASE_ANDROID_APP_ID=1:1234567890:android:abc... \
--dart-define=FIREBASE_IOS_APP_ID=1:1234567890:ios:def... \
--dart-define=FIREBASE_SENDER_ID=1234567890 \
--dart-define=FIREBASE_PROJECT_ID=tingpush-camera
App ID TingPush đã đặt sẵn trong lib/core/config.dart (đổi bằng --dart-define=TINGPUSH_APP_ID=…). API Key không
bao giờ nằm trong app.
iOS (Xcode → Signing & Capabilities): thêm Push Notifications; Background Modes đã khai báo sẵn
(Remote notifications, Voice over IP) trong Info.plist. Android: AndroidManifest.xml đã có showWhenLocked,
turnScreenOn, USE_FULL_SCREEN_INTENT. Firebase chưa cấu hình → app vẫn chạy, mục Cảnh báo AI báo "chưa bật được".
Bản web của app (và máy tính) không có thông báo đẩy; sự kiện vẫn hiện theo thời gian thực khi đang mở.
4. Cấu hình trên camera (/userdata/lpr/ai.conf)
App ghi qua lệnh ai_set (PUT /api/cameras/{id}/ai, body là các khóa dưới đây). Tọa độ chuẩn hóa 0..1 theo khung hình.
| Khóa | Mặc định | Ý nghĩa |
|---|---|---|
plate.enable |
1 | Đọc biển số |
<tính năng>.enable / .schedule / .days / .cooldown_s |
0 / rỗng / 127 / 0·60·300 | Bật, giờ chạy (06:00-18:00,22:00-02:00, rỗng = cả ngày), ngày (bit 0 = CN … bit 6 = T7), chống báo lặp. Tính năng: count, intrusion, face |
count.lines |
Tên|x1,y1,x2,y2;… (tối đa 4). Đi từ trái sang phải vạch (nhìn từ A về B) = vào |
|
count.classes / count.interval_s |
person,vehicle / 60 |
Lớp đếm / chu kỳ gửi số đếm (10–3600 s) |
count.occupancy_max / count.reset_time / count.cooldown_s |
0 / 00:00 / 300 |
Báo quá đông khi số đang ở bên trong ≥ ngưỡng (0 = tắt) / giờ về 0 mỗi ngày / không báo quá đông lại trong (giây) |
intrusion.zones |
Tên|x1,y1,x2,y2,x3,y3,…;… (≥ 3 điểm, tối đa 4 vùng × 12 điểm) |
|
intrusion.classes / intrusion.dwell_s |
person / 2 |
Lớp báo / số giây ở trong vùng |
face.zone / face.threshold / face.unknown |
rỗng / 42 / 0 | Vùng nhận diện / % độ giống (cosine × 100) / báo người lạ |
face.learn / face.learn_days / face.learn_keep |
0 / 7 / 30 | Học khuôn mặt / tự thêm người nhà sau N ngày liên tục (0 = không tự thêm, tối đa 60) / quên nhóm chưa xác nhận sau N ngày không gặp (7–365) |
object.conf / object.ratio |
45 / 1 | % điểm tối thiểu model người / xe / chạy model 1 trên N khung AI |
Xét theo điểm chân đối tượng (tâm cạnh dưới khung). Mỗi người / xe được gán mã theo dõi (IoU qua các khung).
Qua vạch: camera nhớ người đó đang ở phía nào của vạch; mỗi lần chuyển hẳn sang phía kia là 1 lượt (trái → phải nhìn từ
A về B = vào, ngược lại = ra). Dải đệm 2% khung hình hai bên vạch: đứng lắc lư ngay trên vạch không bị đếm; đi vòng qua
đầu mút vạch không đếm. Ở trong vùng cấm chỉ báo 1 lần mỗi lần xâm nhập. Số đang ở bên trong lưu ở /userdata/lpr/ai_state
(ghi mỗi chu kỳ), không âm.
5. Định dạng sự kiện camera gửi
Camera gửi 2 đường, cùng event_id (máy chủ bỏ bản trùng, bản thứ hai chỉ bổ sung ảnh):
- Tức thì (xâm nhập, khuôn mặt): WebSocket
{"type":"ai_event","event":{…không ảnh…}}. - Đầy đủ:
POST https://apiwebrtc.tingpush.com/api/device/events, headerAuthorization: Device <camera_id>:<khóa>, có hàng đợi trên camera (mất mạng gửi lại, tối đa 300 bản).
{
"event_id": "LPR-9MHK902C8J5Z-1792170903-000031",
"type": "intrusion",
"device_id": "CONG-KHO",
"camera_id": "LPR-9MHK902C8J5Z",
"time": "2026-10-16T22:15:03+07:00",
"timestamp": 1792170903,
"summary": "Có người xâm nhập vùng Kho",
"data": { "zone": "Kho", "zone_index": 0, "class": "person", "track_id": 17, "box": [0.67, 0.5, 0.83, 0.8], "dwell_s": 2 },
"image_type": "jpeg", "image": "<ảnh toàn cảnh base64>",
"crop_image_type": "jpeg", "crop_image": "<ảnh cắt đối tượng base64>"
}
type |
data |
|---|---|
intrusion |
zone, zone_index, class (person / vehicle), track_id, box [x1,y1,x2,y2] 0..1, dwell_s |
face |
known (bool), person_id, name (khi quen), similarity 0..1, box. Người lạ khi bật học khuôn mặt: cluster_id, seen_days, seen_visits, first_seen. Camera tự thêm người nhà: known = true, auto_member = true, person_id, name, streak_days (kèm crop_image = ảnh mặt) |
count |
start (giây UNIX đầu chu kỳ), period_s, total_in, total_out, occupancy, lines: [{"name","in":{"person","vehicle"},"out":{…}}] |
io (thiết bị ngoại vi) |
output, output_name, action (pulse / on / off), trigger (luật, hoặc manual), by (lý do / người bấm), plate (khi do biển số), ok, error — xem Thiết bị ngoại vi — mở barie, cửa cuốn, còi, đèn từ camera TingPush. Không tính hạn mức |
occupancy (quá đông) |
occupancy: {"person","vehicle","total","max","day","reset_time"} — total = tổng các lớp đang đếm, day = ngày đếm yyyymmdd |
data.test = true = sự kiện thử (nút Thử): vẫn lưu và báo, không tính hạn mức, số đếm thử không vào thống kê.
Lấy dữ liệu về phần mềm của bạn: GET /api/v1/events, /api/v1/counts — Hướng dẫn API công khai TingPush — lấy dữ liệu biển số đã lưu.
6. API cho app (đăng nhập JWT)
GET /api/events?camera=&type=intrusion,face&before=&limit= |
Danh sách sự kiện (mới nhất trước) |
GET /api/events/{id}/image/scene · /crop |
Ảnh |
GET /api/counts?camera=&from=&to=&bucket=hour\|day\|month&by_line= |
Số đếm |
GET /api/occupancy?camera= |
Số đang ở bên trong từng camera [{"camera","person","vehicle","total","max","updatedAt"}] (sang ngày đếm mới mà camera chưa gửi gì = 0) |
POST /api/cameras/{id}/occupancy {"person":0,"vehicle":0} |
Chủ camera đặt lại / sửa số đang ở bên trong |
GET / PUT /api/cameras/{id}/ai |
Cấu hình + trạng thái AI trên camera (chủ camera) |
POST /api/cameras/{id}/ai/test {"type":"intrusion"} |
Camera tạo sự kiện thử (intrusion, occupancy, face, count; model tùy chỉnh: {"type":"custom","model":"oil"}) |
GET / PUT /api/cameras/{id}/alerts |
Cách báo của người đang đăng nhập: [{"feature","push","call","filter"}] — filter: khuôn mặt all/known/unknown; đếm = ngưỡng lượt vào; biển số = danh sách 30A12345, 51F*. Model tùy chỉnh: feature = c:<id> (GET thêm ?custom=oil,smoke = các model trên camera) |
GET /api/cameras/{id}/models · POST {"package":"oil","version":null} · GET …/models/status · DELETE …/models/{id} |
Model AI trên camera + kho gói máy chủ; cài gói (camera tải, kiểm SHA-256, nạp lại không khởi động lại); tiến trình; xóa model tùy chỉnh |
GET /api/models · admin GET/POST/DELETE /api/admin/models |
Kho gói model (admin tải lên .tar.gz hoặc .rknn + .json) |
GET /api/faces · POST /api/faces (multipart name, note, cameras, image) · PUT /api/faces/{id}/cameras · DELETE /api/faces/{id} |
Thư viện khuôn mặt |
GET /api/cameras/{id}/face-learn · GET …/face-learn/{nhóm}/image · POST …/face-learn/{nhóm}/promote {"name"} · POST …/face-learn/{nhóm}/merge {"other"} · DELETE …/face-learn/{nhóm} · DELETE …/face-learn |
Người hay gặp (chủ camera): danh sách {"enabled","autoDays","keepDays","autoAdded","items":[{"id","firstSeen","lastSeen","visits","days","streak","hours","hasImage"}]}, ảnh mặt, xác nhận người nhà (trả người trong thư viện), gộp nhóm other vào nhóm trên đường dẫn, xóa 1 / tất cả |
POST /api/calls/{callId}/answer |
Đã nghe cuộc gọi cảnh báo → máy khác tắt chuông |
GET /api/me/push |
appId, externalId cho SDK TingPush |
WebSocket /ws/view |
Thêm tin {"type":"ai_event","event":{…}} khi có sự kiện mới / khi ảnh tới |
Dữ liệu cảnh báo kèm thông báo (data): screen = event (mở chi tiết, event_id), live (cuộc gọi, camera,
call_id), plates (biển số theo dõi).
7. Nạp model (lập trình viên firmware)
Mã nguồn: lpr_camera/src/app/ai_logic.c (theo dõi, vạch, vùng, so khớp khuôn mặt — test trên PC),
ai_engine.c (lịch, chống lặp, dựng sự kiện, ảnh), ai_config.c, src/lpr/lpr_ai.cpp (chạy model trên NPU).
Người / xe: đặt models/object.rknn — YOLO COCO 80 lớp, INT8 rv1126b, tọa độ khung chuẩn hóa 0..1: tạo bằng
tools/make_object_rknn.py (bản yolo export format=rknn mới của Ultralytics để tọa độ theo pixel → không dùng được). lpr_ai.cpp thu nhỏ khung NV12 → BGR 640 điểm ngang,
lớp 0 → người; 1, 2, 3, 5, 7 (xe đạp, ô tô, xe máy, buýt, tải) → xe; chỉ chạy khi có tính năng bật trong giờ chạy.
Model khác (VD chỉ 2 lớp) → sửa OBJECT_NC và coco_to_ai().
Khuôn mặt: cần 2 phần, cùng một model nhận dạng (vector 128 chiều, AI_FACE_DIM):
- Mỗi khung: phát hiện mặt + tính vector → gọi
ai_engine_on_face(vector, box_0_1, &frame, lpr_now_mono(), time(NULL))(engine tự chuẩn hóa vector, so cosine với thư viện, áp ngưỡng / vùng / chống lặp, gửi sự kiện). - Thêm người: cài
lpr_platform_t.face_embed(jpeg_path, out[128], err, cap)— tính vector từ ảnh chân dung mà máy chủ gửi (lệnhface_enroll, link ảnh có hạn 10 phút). Thư viện lưu ở/userdata/lpr/faces.db.
Báo trạng thái model cho app: ai_engine_set_model(0 | 1, loaded, "lỗi").
Model tùy chỉnh (vết dầu loang, khói…, không sửa code): models/custom/<id>.rknn + <id>.json, sự kiện loại
custom (data.model, model_name, class, box, duration_s, level, zone). Xem
Thêm model AI mới cho camera (không sửa code).
8. Thử khi chưa có model / chưa có thiết bị
- App: Tính năng AI & cảnh báo → Thử cảnh báo xâm nhập / quá đông / khuôn mặt (camera tạo sự kiện mẫu kèm ảnh chụp).
- Giả lập trên PC (
make sim, xemlpr_camera/README.md), gõ vào stdin:
obj person 0.9 0.42 0.5 0.58 0.8 # 1 khung: người (lớp điểm x1 y1 x2 y2), lặp nhiều dòng để đi
obj person 0.9 0.45 0.5 0.61 0.8 vehicle 0.8 0.1 0.4 0.3 0.7
obj # khung không có ai
face 111 0.4 0.2 0.5 0.4 # khuôn mặt có vector giả "chiều 111"
Khi thêm người trên app, giả lập in ra chiều vector của ảnh đó để gõ face <k> … nhận diện người này.