Update Today

This commit is contained in:
proitlab committed 2026-08-03 16:26:01 +07:00
1 parent 896a07b5fa
commit eefff48953
7 files changed
+2827 -12

No files matched your search

+2781 -7
View File
File diff suppressed because it is too large. Load diff
+20
View File
@@ -33,3 +33,23 @@ make -j$(nproc)
systemctl restart bytetrack-counter
journalctl -u bytetrack-counter -f
```
## Reset via .reset file
Place a `.reset` file in `SHM_DIR` (default `/dev/shm/bytetrack-counter`) to trigger a full state reset:
- **Startup**: deleting `.reset` before service starts clears all state files on boot
- **Runtime**: dropping `.reset` while service runs calls `BatchStore::reset()` — ends active batch, clears in-memory state, deletes `STATE_FILE`, clears live stream JPEG + writes blank frame on next write
```bash
touch /dev/shm/bytetrack-counter/.reset
```
## Shared memory
`SHM_DIR` (`/dev/shm/bytetrack-counter` by default) stores:
- `LIVE_STREAM_FRAME_PATH` JPEG snapshot
- `RECORD_SHM_DIR` video recordings before move to disk
- `.reset` trigger file
Directory auto-created at startup.
+10 -3
View File
@@ -20,12 +20,16 @@ Talenan crossing → close batch. Persist to SQLite + JSON.
```
env: .env KEY=VALUE file — all config per config.env.example
env: LIVE_STREAM_FRAME_PATH → JPEG snapshot path (/dev/shm/bytetrack-counter/live_frame.jpg)
env: SHM_DIR → shared memory directory (/dev/shm/bytetrack-counter)
env: LIVE_STREAM_FRAME_PATH → JPEG snapshot path
env: RECORD_VIDEO, RECORD_DELAY_SECONDS, RECORD_END_DELAY, RECORD_RETENTION_DAYS
cmd: bytetrack-counter <config.env>
db: SQLite batches(id,counting_date,batch_number,camera_name,object_label,count,start_time,end_time)
db: SQLite daily_summaries(id,counting_date,camera_name,object_label,total_count,total_batches)
file: JSON state — batch_number,count,start_time,last_detection_time,counted_event_ids[]
file: CSV crossing log — batch,frame,timestamp,chicken_id
file: SHM_DIR/.reset → trigger full state reset
file: SHM_DIR/batch_N_HHMMSS.mp4 → per-batch video recording (moved to OUTPUT_DIR/YYYY-MM-DD/)
sig: SIGTERM|SIGINT → shutdown_requested → graceful exit
```
@@ -42,7 +46,10 @@ V7: counting_date rolls at DAILY_CUTOFF_TIME → cutoff_watcher thread
V8: ayam & talenan → separate ByteTrack instances (match_thresh_0=0.8, match_thresh_1=0.6)
V9: live_stream_enabled → parent dir of LIVE_STREAM_FRAME_PATH created @ startup
V10: stale track (> TRACKED_PRUNE_SEC unseen) → prune from external tracking maps
V11: DIRECTORY for LIVE_STREAM_FRAME_PATH must exist — created by code and by tmpfiles.d on boot (/dev/shm is volatile)
V11: all dirs (output_dir, shm_dir, live_stream parent) created @ startup
V12: SHM_DIR/.reset → BatchStore::reset() — end active batch, clear memory, delete state_file, write blank live JPEG
V13: video recording: motion → SPECULATING (≤RECORD_DELAY_SECONDS), ayam → CONFIRMED → talenan/batch-end → STOPPING (+RECORD_END_DELAY) → move to OUTPUT_DIR/YYYY-MM-DD/
V14: video retention: day-dirs > RECORD_RETENTION_DAYS old → removed @ startup & @ each CUTOFF_TIME
```
## §T — Tasks
@@ -64,7 +71,7 @@ T12|x|CsvLogger for crossing events|I.file
T13|x|Live JPEG snapshot to shared memory|V9
T14|x|systemd service with ProtectSystem + ReadWritePaths|I.cmd
T15|x|Graceful shutdown: SIGTERM → close batch → save state|I.sig
T16|x|Video per batch recording (config exists, impl ⊥ in C++) to shared memory for speed reason. To identify batch is between talenan (index=1), save with different name. Once completed, spawn new process (non blocking) to move recorded file to final destination (from config env). To identify first batch, record and wait X seconds (X default is 10 seconds, can be defined in config env), until first ayam (index=0) detected|-
T16|x|Video per-batch recording: motion-triggered → speculating in shm, confirmed when ayam detected ≤ RECORD_DELAY_SECONDS, stopped RECORD_END_DELAY after batch close, moved to OUTPUT_DIR/YYYY-MM-DD/ via fork, retention cleanup at startup & cutoff. Unconfirmed recordings deleted.|V13,V14
T17|~?|Python DEBUG_TRACKING equivalent (per-frame score/track dump)|-
```
Binary file not shown.
+11
View File
@@ -413,6 +413,17 @@ void BatchStore::set_batch_closed_callback(std::function<void(int)> cb) {
batch_closed_cb_ = std::move(cb);
}
void BatchStore::reset() {
std::lock_guard<std::mutex> lock(state_mutex_);
if (!current_state_.is_null()) {
end_batch_locked("reset");
}
current_state_ = nullptr;
batch_timer_running_ = false;
std::error_code ec;
std::filesystem::remove(state_file_, ec);
}
bool BatchStore::check_cutoff_reset() {
return cutoff_triggered_.exchange(false);
}
+1
View File
@@ -32,6 +32,7 @@ public:
int display_total();
void set_batch_closed_callback(std::function<void(int)> cb);
void reset();
bool check_cutoff_reset();
+4 -2
View File
@@ -150,12 +150,13 @@ int main(int argc, char* argv[]) {
std::filesystem::create_directories(live_p.parent_path());
}
bool startup_reset = false;
{
std::string reset_file = g_config.shm_dir + "/.reset";
if (std::filesystem::exists(reset_file)) {
std::cout << "[RESET] [INFO] .reset detected — clearing state" << std::endl;
startup_reset = true;
std::error_code ec;
std::filesystem::remove(g_config.state_file, ec);
std::filesystem::remove(g_config.live_stream_frame_path, ec);
std::filesystem::remove(reset_file, ec);
}
@@ -177,6 +178,7 @@ int main(int argc, char* argv[]) {
g_config.min_duration_per_batch,
logger);
store.start_cutoff_watcher();
if (startup_reset) store.reset();
std::unique_ptr<CsvLogger> cross_logger;
if (g_config.export_csv) {
@@ -258,8 +260,8 @@ int main(int argc, char* argv[]) {
std::string reset_file = g_config.shm_dir + "/.reset";
if (std::filesystem::exists(reset_file)) {
std::cout << "[" << now_str() << "] [INFO] [RESET] .reset detected — clearing state" << std::endl;
store.reset();
std::error_code ec;
std::filesystem::remove(g_config.state_file, ec);
std::filesystem::remove(g_config.live_stream_frame_path, ec);
std::filesystem::remove(reset_file, ec);
blank_live_frame = true;