#include "config.hpp" #include #include #include #include AppConfig g_config; static std::string trim(const std::string& s) { auto start = s.find_first_not_of(" \t\r\n"); if (start == std::string::npos) return {}; auto end = s.find_last_not_of(" \t\r\n"); return s.substr(start, end - start + 1); } static std::string get_env(const std::string& key, const std::string& def = "") { const char* val = std::getenv(key.c_str()); return val ? std::string(val) : def; } void AppConfig::load_from_env(const char* env_path) { std::string path = ".env"; if (env_path) path = env_path; // also check env path const char* env_file = std::getenv("ENV_FILE"); if (env_file) path = env_file; std::ifstream file(path); if (file.is_open()) { std::string line; while (std::getline(file, line)) { line = trim(line); if (line.empty() || line[0] == '#') continue; auto eq = line.find('='); if (eq == std::string::npos) continue; std::string key = trim(line.substr(0, eq)); std::string val = trim(line.substr(eq + 1)); // strip quotes if (val.size() >= 2 && val.front() == '"' && val.back() == '"') val = val.substr(1, val.size() - 2); setenv(key.c_str(), val.c_str(), 1); } } output_dir = get_env("OUTPUT_DIR", output_dir); db_path = get_env("DB_PATH", output_dir + "/bytetrack_counter.db"); state_file = get_env("STATE_FILE", output_dir + "/current_batch.json"); source = get_env("SOURCE", source); model_path = get_env("MODEL_PATH", model_path); camera_name = get_env("CAMERA_NAME", camera_name); object_label = get_env("OBJECT_LABEL", object_label); class_ayam = get_env("CLASS_AYAM", class_ayam); class_talenan = get_env("CLASS_TALENAN", class_talenan); auto lx = get_env("LINE_X"); if (!lx.empty()) line_x = std::stoi(lx); auto lxf = get_env("LINE_X_FRAC"); if (!lxf.empty()) line_x_frac = std::stof(lxf); cross_direction = get_env("CROSS_DIRECTION", cross_direction); auto imgsz_s = get_env("IMGSZ"); if (!imgsz_s.empty()) imgsz = std::stoi(imgsz_s); auto half_s = get_env("HALF"); half = (half_s == "true"); auto conf_s = get_env("CONF"); if (!conf_s.empty()) conf = std::stof(conf_s); auto dev_s = get_env("DEVICE"); if (!dev_s.empty()) device = std::stoi(dev_s); auto cm_s = get_env("CORE_MASK"); if (!cm_s.empty()) core_mask = std::stoi(cm_s); auto nc_s = get_env("NUM_CLASSES"); if (!nc_s.empty()) num_classes = std::stoi(nc_s); auto ss_s = get_env("SCORE_SIGMOID"); score_sigmoid = (ss_s == "true"); auto ac_s = get_env("AYAM_CLASS_ID"); if (!ac_s.empty()) ayam_class_id = std::stoi(ac_s); auto tc_s = get_env("TALENAN_CLASS_ID"); if (!tc_s.empty()) talenan_class_id = std::stoi(tc_s); auto th0_s = get_env("TRACK_HIGH_THRESH_0"); if (!th0_s.empty()) track_high_thresh_0 = std::stof(th0_s); auto tl0_s = get_env("TRACK_LOW_THRESH_0"); if (!tl0_s.empty()) track_low_thresh_0 = std::stof(tl0_s); auto tm0_s = get_env("TRACK_MATCH_THRESH_0"); if (!tm0_s.empty()) track_match_thresh_0 = std::stof(tm0_s); auto tb0_s = get_env("TRACK_BUFFER_0"); if (!tb0_s.empty()) track_buffer_0 = std::stoi(tb0_s); auto tmh0_s = get_env("TRACK_MIN_HITS_0"); if (!tmh0_s.empty()) track_min_hits_0 = std::stoi(tmh0_s); auto th1_s = get_env("TRACK_HIGH_THRESH_1"); if (!th1_s.empty()) track_high_thresh_1 = std::stof(th1_s); auto tl1_s = get_env("TRACK_LOW_THRESH_1"); if (!tl1_s.empty()) track_low_thresh_1 = std::stof(tl1_s); auto tm1_s = get_env("TRACK_MATCH_THRESH_1"); if (!tm1_s.empty()) track_match_thresh_1 = std::stof(tm1_s); auto tb1_s = get_env("TRACK_BUFFER_1"); if (!tb1_s.empty()) track_buffer_1 = std::stoi(tb1_s); auto tmh1_s = get_env("TRACK_MIN_HITS_1"); if (!tmh1_s.empty()) track_min_hits_1 = std::stoi(tmh1_s); auto rw_s = get_env("RATE_WINDOW_SEC"); if (!rw_s.empty()) rate_window_sec = std::stoi(rw_s); daily_cutoff_time = get_env("DAILY_CUTOFF_TIME", daily_cutoff_time); auto rcc_s = get_env("RESET_COUNTERS_AT_CUTOFF"); if (!rcc_s.empty()) reset_counters_at_cutoff = (rcc_s == "true"); auto bto_s = get_env("BATCH_TIMEOUT_SECONDS"); if (!bto_s.empty()) batch_timeout_seconds = std::stof(bto_s); auto ibl_s = get_env("IGNORE_BATCH_LABEL_TIMEOUT_SECONDS"); if (!ibl_s.empty()) ignore_batch_label_timeout = std::stof(ibl_s); auto mob_s = get_env("MIN_OBJECT_PER_BATCH"); if (!mob_s.empty()) min_object_per_batch = std::stoi(mob_s); auto mdb_s = get_env("MIN_DURATION_PER_BATCH"); if (!mdb_s.empty()) min_duration_per_batch = std::stoi(mdb_s); auto ecsv = get_env("EXPORT_CSV"); if (!ecsv.empty()) export_csv = (ecsv == "true"); cross_csv = get_env("CROSS_CSV", output_dir + "/batch_crossings.csv"); auto mde_s = get_env("MOTION_DETECTION_ENABLED"); motion_detection_enabled = (mde_s == "true"); auto mt_s = get_env("MOTION_THRESHOLD"); if (!mt_s.empty()) motion_threshold = std::stof(mt_s); auto wf_s = get_env("WARMUP_FRAMES"); if (!wf_s.empty()) warmup_frames = std::stoi(wf_s); auto rd_s = get_env("RECONNECT_DELAY_SEC"); if (!rd_s.empty()) reconnect_delay_sec = std::stoi(rd_s); auto mra_s = get_env("MAX_RECONNECT_ATTEMPTS"); if (!mra_s.empty()) max_reconnect_attempts = std::stoi(mra_s); auto fl_s = get_env("FLUSH_EVERY_N_FRAMES"); if (!fl_s.empty()) flush_every_n_frames = std::stoi(fl_s); auto tp_s = get_env("TRACKED_PRUNE_SEC"); if (!tp_s.empty()) tracked_prune_sec = std::stoi(tp_s); auto rv_s = get_env("RECORD_VIDEO"); record_video = (rv_s == "true"); auto vs_s = get_env("VIDEO_SEGMENT_SEC"); if (!vs_s.empty()) video_segment_sec = std::stoi(vs_s); auto ofps_s = get_env("OUTPUT_FPS"); if (!ofps_s.empty()) output_fps = std::stoi(ofps_s); auto rds_s = get_env("RECORD_DELAY_SECONDS"); if (!rds_s.empty()) record_delay_seconds = std::stof(rds_s); auto reds_s = get_env("RECORD_END_DELAY"); if (!reds_s.empty()) record_end_delay_seconds = std::stof(reds_s); auto rret_s = get_env("RECORD_RETENTION_DAYS"); if (!rret_s.empty()) record_retention_days = std::stoi(rret_s); shm_dir = get_env("RECORD_SHM_DIR", shm_dir); shm_dir = get_env("SHM_DIR", shm_dir); auto lse_s = get_env("LIVE_STREAM_ENABLED"); live_stream_enabled = (lse_s == "true"); live_stream_frame_path = get_env("LIVE_STREAM_FRAME_PATH", live_stream_frame_path); auto lsq_s = get_env("LIVE_STREAM_QUALITY"); if (!lsq_s.empty()) live_stream_quality = std::stoi(lsq_s); auto lsn_s = get_env("LIVE_STREAM_EVERY_N"); if (!lsn_s.empty()) live_stream_every_n = std::stoi(lsn_s); rtsp_ffmpeg_options = get_env("OPENCV_FFMPEG_CAPTURE_OPTIONS", rtsp_ffmpeg_options); }