diff --git a/counter_snapshot.ds b/counter_snapshot.ds
new file mode 100755
index 0000000..418d686
--- /dev/null
+++ b/counter_snapshot.ds
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+WORKDIR=/etc/frigate
+PYTHON_EXEC=${WORKDIR}/counter_snapshot.py
+
+CURRENT_DATE=`date +%Y-%m-%d`
+CAMERA_NAME="kandang_1_karung_pakan"
+
+${PYTHON_EXEC} ${CAMERA_NAME} ${CURRENT_DATE}
diff --git a/counter_snapshot.py b/counter_snapshot.py
new file mode 100755
index 0000000..0420b72
--- /dev/null
+++ b/counter_snapshot.py
@@ -0,0 +1,177 @@
+#!/usr/bin/python3
+
+import sys
+import sqlite3
+from pathlib import Path
+from datetime import datetime, timedelta
+
+def list_files_with_extension(directory_path, extension):
+ """
+ Lists files in a directory with a specific extension using pathlib.Path.glob().
+
+ Args:
+ directory_path (str): The path to the directory.
+ extension (str): The desired file extension (e.g., '.txt', '.py').
+
+ Returns:
+ list: A list of Path objects for files with the specified extension.
+ """
+ path_obj = Path(directory_path)
+ file_list = [f.name for f in path_obj.iterdir() if f.is_file() and f.suffix == extension]
+ return file_list
+
+def list_files_pathlib(directory_path):
+ """Lists all files in a given directory using the pathlib module."""
+ files_list = []
+ path = Path(directory_path)
+ for item in path.iterdir():
+ if item.is_file():
+ files_list.append(item.name) # Appends only the file name
+ return files_list
+
+def get_start_end_timestamp(data_date: str = None) -> [int, int]:
+ start_ts = end_ts = 0
+ if data_date:
+ format_string = "%Y-%m-%d"
+ try:
+ end_date = datetime.strptime(data_date, format_string)
+ end_time = end_date.replace(hour=17, minute=0, second=0)
+ start_time = end_time - timedelta(days=1)
+ start_ts = int(start_time.timestamp())
+ end_ts = int(end_time.timestamp())
+
+ except ValueError:
+ print(f"Value {start_date} must be in format '%Y-%m-%d'")
+ sys.exit(1)
+
+ else:
+ start_time = end_time = datetime.now()
+ if end_time.hour < 17:
+ start_time = end_time - timedelta(days=1)
+
+ start_time = start_time.replace(hour=17, minute=0, second=0, microsecond=0)
+
+ start_ts = int(start_time.timestamp())
+ end_ts = int(end_time.timestamp())
+
+ return start_ts, end_ts
+
+
+def get_ts_from_file(file: str) -> int:
+ file_split = file.split("-")
+ ts_int = int(float(file_split[1]))
+
+ return ts_int
+
+
+def get_files(start_ts: int = 0, end_ts: int = 0, camera_name: str = None) -> list:
+ directory = "/var/lib/docker/volumes/frigate_storage/_data/clips" # Current directory
+ files = list_files_with_extension(directory, ".jpg")
+
+ files_list = []
+ for file in files:
+ ts_int = get_ts_from_file(file)
+ if ts_int >= start_ts:
+ if end_ts == 0:
+ if camera_name in file:
+ files_list.append(file)
+ elif ts_int < end_ts:
+ if camera_name in file:
+ files_list.append(file)
+
+ return files_list
+
+
+def check_duplicate(files: list = []) -> list:
+ DETIK_ANTAR_KARUNG = 30
+ files_nodup = []
+ for i in range(len(files)-1):
+ ts_current = get_ts_from_file(files[i])
+ ts_next = get_ts_from_file(files[i+1])
+ if ts_next - ts_current > DETIK_ANTAR_KARUNG:
+ files_nodup.append(files[i])
+
+ return files_nodup
+
+
+def store_in_db(date_ts: int, camera_name: str, value: int, value_nodup: int):
+
+ print(str(datetime.now()), f"Get {date_ts} {camera_name} {value} {value_nodup}")
+ DB_FILE = "/etc/frigate/counter.db"
+ conn = sqlite3.connect(DB_FILE)
+ cursor = conn.cursor()
+
+ # Create DB
+ create_sql = '''CREATE TABLE IF NOT EXISTS counter (
+ id INTEGER PRIMARY KEY,
+ date_ts INTEGER,
+ camera_name TEXT,
+ value INTEGER,
+ value_nodup INTEGER
+ )
+ '''
+
+ cursor.execute(create_sql)
+
+ # Start Checkin DB
+ allrows = []
+ try:
+ cursor.execute("SELECT * FROM counter where date_ts=? and camera_name=?", (date_ts, camera_name))
+ allrows = cursor.fetchall()
+
+ except sqlite3.OperationalError:
+ print(str(datetime.now()), f"Error")
+
+ if len(allrows):
+ # UPDATE
+ print(str(datetime.now()), f"Found record. Update DB")
+ update_sql = "UPDATE counter SET value = ?, value_nodup = ? WHERE date_ts = ? and camera_name = ?"
+ cursor.execute(update_sql, (date_ts, camera_name, value, value_nodup))
+
+ else:
+ # INSERT
+ print(str(datetime.now()), f"Insert into DB")
+ insert_sql = "INSERT INTO counter (date_ts, camera_name, value, value_nodup) VALUES (?, ?, ?, ?)"
+ cursor.execute(insert_sql, (date_ts, camera_name, value, value_nodup))
+
+ conn.commit()
+ conn.close()
+
+
+end_date = None
+
+if len(sys.argv) > 2:
+ camera_name = sys.argv[1]
+ end_date = sys.argv[2]
+ start_ts, end_ts = get_start_end_timestamp(end_date)
+elif len(sys.argv) > 1:
+ camera_name = sys.argv[1]
+ start_ts, end_ts = get_start_end_timestamp()
+else:
+ print("================")
+ print("Counter Snapshot")
+ print("================\n")
+ print(f"Usage:")
+ print(f"\tpython3 {sys.argv[0]} [camera_name] [data_date]\n")
+ print(f"Example:")
+ print(f"\tpython3 {sys.argv[0]} kandang_1_karung_pakan")
+ print(f"\tpython3 {sys.argv[0]} kandang_1_karung_pakan 2025-09-23 -> data from 2025-09-22 17:00:00 to 2025-09-23 16:59:59")
+ sys.exit(1)
+
+#print(start_ts, end_ts, camera_name)
+files = get_files(start_ts, end_ts, camera_name)
+
+files_nodup = check_duplicate(files)
+
+value = len(files)
+value_nodup = len(files_nodup)
+#print(value)
+#print(value_nodup)
+
+if end_date:
+ store_in_db(end_ts, camera_name, value, value_nodup)
+ print(str(datetime.now()), f"Store in DB {end_ts}/{camera_name}/{value}/{value_nodup}")
+
+#for file in files_nodup:
+# print(file)
+
diff --git a/frigate_counter.py b/frigate_counter.py
new file mode 100644
index 0000000..aa9df3c
--- /dev/null
+++ b/frigate_counter.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env python3
+import json
+import threading
+import paho.mqtt.client as mqtt
+import os
+import sqlite3
+from datetime import datetime, timedelta
+
+# =====================
+# SITE CONFIG
+# =====================
+TOP_TOPIC = "cpsp"
+SITE_NAME = "sukawarna"
+SITE_TOPIC = f"{TOP_TOPIC}/counter/{SITE_NAME}"
+
+# =====================
+# KONFIGURASI MQTT
+# =====================
+BROKER = "localhost" # ganti sesuai broker
+PORT = 1883
+USERNAME = "" # ganti user
+PASSWORD = "" # ganti password
+TOPIC = "frigate/events"
+
+# =====================
+# MQTT PUBLISH
+# =====================
+#PUBLISH_BROKER = "localhost"
+PUBLISH_BROKER = "mqtt.backone.cloud"
+PUBLISH_PORT = 1883
+USERNAME = "" # ganti user
+PASSWORD = "" # ganti password
+
+# =====================
+# FILE COUNTER
+# =====================
+DATA_FILE = "/etc/frigate-counter/karung-tuang/karung_tuang.json"
+
+# =====================
+# DATABASE INITIALIZATION
+# =====================
+DB_FILE = "/etc/frigate-counter/karung-tuang/karung_tuang.db"
+
+
+def init_database():
+ """Initialize the SQLite database with the required table"""
+ conn = sqlite3.connect(DB_FILE)
+ cursor = conn.cursor()
+
+ # Create table if it doesn't exist
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS counter_data (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ camera_name TEXT NOT NULL,
+ date TIMESTAMP NOT NULL,
+ counter_value INTEGER NOT NULL
+ )
+ """
+ )
+
+ conn.commit()
+ conn.close()
+
+
+# Initialize the database
+init_database()
+
+# =====================
+# INISIALISASI COUNTER
+# =====================
+if os.path.exists(DATA_FILE):
+ with open(DATA_FILE, "r") as f:
+ counter = json.load(f)
+else:
+ counter = {
+ "kandang_atas_feeder_kiri": {"karung": 0},
+ "kandang_bawah_feeder_kanan": {"karung": 0},
+ }
+ with open(DATA_FILE, "w") as f:
+ json.dump(counter, f, indent=2)
+
+camera_feeder_no_duplicate = [
+ "kandang_atas_feeder_kiri",
+ "kandang_bawah_feeder_kanan"
+ ]
+
+camera_feeder = [
+ "kandang_atas_feeder_kiri",
+ "kandang_bawah_feeder_kanan"
+ ]
+
+camera_masuk = ["kandang_1_karung_masuk"]
+
+# Untuk debounce object per track_id
+seen_objects = {} # dict per kamera: {track_id: last_seen}
+
+
+# =====================
+# FUNGSI SAVE COUNTER
+# =====================
+def save_counter():
+ with open(DATA_FILE, "w") as f:
+ json.dump(counter, f, indent=2)
+
+
+def save_counter_to_database(camera_list_to_save=[]):
+ """Save current counter values to SQLite database"""
+ conn = sqlite3.connect(DB_FILE)
+ cursor = conn.cursor()
+
+ # Get current timestamp
+ current_time = datetime.now()
+
+ # Save each counter value to database
+ for camera_name, camera_data in counter.items():
+ for label, value in camera_data.items():
+ if label == "karung" and camera_name in camera_list_to_save: # Only save karung counters
+ cursor.execute(
+ """
+ INSERT INTO counter_data (camera_name, date, counter_value)
+ VALUES (?, ?, ?)
+ """,
+ (camera_name, current_time, value),
+ )
+
+ conn.commit()
+ conn.close()
+
+
+def republish_counter():
+ # Publish current counter
+ for camera, v in counter.items():
+ for label, value in v.items():
+ if label == "karung":
+ print(f"{SITE_TOPIC}/{camera}/{label}", value)
+ client_publish.publish(
+ f"{SITE_TOPIC}/{camera}/{label}", value, qos=1, retain=True
+ )
+
+
+# =====================
+# RESET HARIAN
+# =====================
+def reset_counter():
+ global counter, seen_objects
+ print(f"[{datetime.now()}] Reset counter otomatis")
+ # Save current counter values to database before reset
+ save_counter_to_database(camera_feeder)
+ # reset semua
+ # for cam in counter:
+ # for obj in counter[cam]:
+ # counter[cam][obj] = 0
+ for camera_name in camera_feeder:
+ counter[camera_name]["karung"] = 0
+
+ """
+ counter["kandang_1_karung_pakan"]["karung"] = 0
+ counter["kandang_2_karung_pakan"]["karung"] = 0
+ counter["kandang_atas_feeder_kiri"]["karung"] = 0
+ counter["kandang_bawah_feeder_kanan"]["karung"] = 0
+ """
+ seen_objects = {}
+ save_counter()
+ schedule_reset() # jadwalkan besok
+ republish_counter()
+
+
+def reset_counter_masuk():
+ global counter, seen_objects
+ print(f"[{datetime.now()}] Reset counter otomatis")
+ # Save current counter values to database before reset
+ save_counter_to_database(camera_masuk)
+ # reset semua
+ # for cam in counter:
+ # for obj in counter[cam]:
+ # counter[cam][obj] = 0
+ for camera_name in camera_masuk:
+ counter[camera_name]["karung"] = 0
+
+ counter["kandang_1_karung_masuk"]["karung"] = 0
+
+ seen_objects = {}
+ save_counter()
+ schedule_reset_masuk() # jadwalkan besok
+ republish_counter()
+
+
+def schedule_reset():
+ now = datetime.now()
+ reset_time = now.replace(hour=17, minute=0, second=0, microsecond=0)
+ if now >= reset_time:
+ reset_time += timedelta(days=1)
+ delay = (reset_time - now).total_seconds()
+ threading.Timer(delay, reset_counter).start()
+ print(f"Reset counter dijadwalkan pada: {reset_time}")
+
+
+def schedule_reset_masuk():
+ now = datetime.now()
+ reset_time = now.replace(hour=23, minute=59, second=55, microsecond=0)
+ if now >= reset_time:
+ reset_time += timedelta(days=1)
+ delay = (reset_time - now).total_seconds()
+ threading.Timer(delay, reset_counter_masuk).start()
+ print(f"Reset counter dijadwalkan pada: {reset_time}")
+
+
+# =====================
+# CALLBACK MQTT
+# =====================
+def on_connect(client, userdata, flags, rc):
+ print("Connected to MQTT with result code " + str(rc))
+ client.subscribe(TOPIC)
+
+
+def on_connect_publish(client, userdata, flags, rc):
+ print("Connected to MQTT PUBLISH with result code " + str(rc))
+ # Publish current counter
+ republish_counter()
+
+
+def on_message(client, userdata, msg):
+ try:
+ payload = json.loads(msg.payload.decode())
+ if "after" not in payload:
+ return
+
+ event_after = payload["after"]
+ event_before = payload.get("before", {})
+
+ camera = event_after.get("camera")
+ label = event_after.get("label")
+ track_id = event_after.get("id")
+ zones_after = event_after.get("entered_zones", [])
+ zones_before = event_before.get("entered_zones", [])
+
+ # Dont detect stationary
+ stationary = event_after.get("stationary")
+ if stationary:
+ return
+
+ # ambil zona baru yg sebelumnya belum ada
+ new_zones = [z for z in zones_after if z not in zones_before]
+
+ # DEDY Don't count camera_masuk. Only count camera feeder
+ #if camera not in camera_feeder:
+ # return
+
+ if not camera or not label:
+ return
+ if camera not in counter or label not in counter[camera]:
+ return
+ if not new_zones: # hanya hitung kalau masuk zona baru
+ return
+
+ # debounce per track_id
+ if camera not in seen_objects:
+ seen_objects[camera] = {}
+ if track_id in seen_objects[camera]:
+ return # sudah dihitung
+
+ # Check if timestamp is more than 30 seconds
+ # if camera == "kandang_1_karung_pakan" or camera == "kandang_2_karung_pakan":
+ """
+ if (
+ camera == "kandang_1_karung_pakan"
+ or camera == "kandang_2_karung_pakan"
+ or camera == "kandang_atas_feeder_kiri"
+ or camera == "kandang_bawah_feeder_kanan"
+ ):
+ """
+ if camera in camera_feeder:
+ DETIK_ANTAR_KARUNG = 35
+ current_time = datetime.now()
+ for ts in seen_objects[camera].values():
+ delta = current_time - ts
+ if delta.seconds < DETIK_ANTAR_KARUNG:
+ return
+
+ # hitung
+ counter[camera][label] += 1
+ seen_objects[camera][track_id] = datetime.now()
+
+ print(
+ f"[{datetime.now()}] Kamera {camera}: Object {label} masuk zona {new_zones}"
+ )
+ print(f"Total {label} di {camera}: {counter[camera][label]}")
+
+ print(f"{TOP_TOPIC}/counter/{SITE_NAME}/{camera}/{label}")
+
+ # simpan dan publish
+ save_counter()
+ #save_counter_to_database(camera_feeder)
+ # client_publish.publish(f"{TOP_TOPIC}/counter/{SITE_NAME}/{camera}/{label}", counter[camera][label], qos=1, retain=True)
+ client_publish.publish(
+ f"{SITE_TOPIC}/{camera}/{label}", counter[camera][label], qos=1, retain=True
+ )
+
+ except Exception as e:
+ print("Error parsing message:", e)
+
+
+def view_database():
+ """View all records in the database"""
+ conn = sqlite3.connect(DB_FILE)
+ cursor = conn.cursor()
+
+ cursor.execute("SELECT * FROM counter_data ORDER BY date DESC LIMIT 10")
+ rows = cursor.fetchall()
+
+ print("Last 10 records in database:")
+ for row in rows:
+ print(f"ID: {row[0]}, Camera: {row[1]}, Date: {row[2]}, Counter: {row[3]}")
+
+ conn.close()
+
+# =====================
+# MAIN
+# =====================
+client = mqtt.Client()
+client.username_pw_set(USERNAME, PASSWORD)
+client.on_connect = on_connect
+client.on_message = on_message
+
+client.connect(BROKER, PORT, 60)
+
+client_publish = mqtt.Client()
+client_publish.on_connect = on_connect_publish
+client_publish.connect(PUBLISH_BROKER, PUBLISH_PORT, 60)
+
+
+# jadwalkan reset pertama
+schedule_reset()
+#schedule_reset_masuk()
+
+client_publish.loop_start()
+print(f"MQTT Publish Counter berjalan di {PUBLISH_BROKER}")
+print(f"MQTT Counter berjalan di {BROKER}")
+client.loop_forever()
diff --git a/karung_tuang.db b/karung_tuang.db
new file mode 100644
index 0000000..836890c
Binary files /dev/null and b/karung_tuang.db differ
diff --git a/karung_tuang.json b/karung_tuang.json
new file mode 100644
index 0000000..22e5217
--- /dev/null
+++ b/karung_tuang.json
@@ -0,0 +1,8 @@
+{
+ "kandang_atas_feeder_kiri": {
+ "karung": 12
+ },
+ "kandang_bawah_feeder_kanan": {
+ "karung": 16
+ }
+}
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..44dbe40
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,170 @@
+
+
+
+
+
+ Frigate Counter Karung Tuang Feeder
+
+
+
+
+
Frigate Counter Karung Tuang Feeder
+
+
+
Counter Summary
+
+
+
+ | Camera Name |
+ Latest Date |
+ Counter Value |
+
+
+
+ {% for item in summary_data %}
+
+ | {{ item.camera_name }} |
+ {{ item.latest_date }} |
+ {{ item.counter_value }} |
+
+ {% endfor %}
+
+
+
+
+
+
Counter Data by Camera and Date
+
+
+
+ | Camera Name |
+ {% for date in pivoted_data.dates %}
+ {{ date }} |
+ {% endfor %}
+
+
+
+ {% for row in pivoted_data.matrix %}
+
+ | {{ row.camera_name }} |
+ {% for date in pivoted_data.dates %}
+ {{ row[date] }} |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+
+
+
Full Counter Data
+
+
+
+ | ID |
+ Camera Name |
+ Date |
+ Counter Value |
+
+
+
+ {% for item in counter_data %}
+
+ | {{ item.id }} |
+ {{ item.camera_name }} |
+ {{ item.date }} |
+ {{ item.counter_value }} |
+
+ {% endfor %}
+
+
+
+
+
+ Last updated: {{ current_time.strftime('%Y-%m-%d %H:%M:%S') }}
+
+
+
+
+
+
diff --git a/web_app.py b/web_app.py
new file mode 100644
index 0000000..5e77668
--- /dev/null
+++ b/web_app.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python3
+import sqlite3
+from flask import Flask, render_template, jsonify
+from datetime import datetime
+import os
+from collections import defaultdict
+
+# Configuration
+DB_FILE = "/etc/frigate/counter_database.db"
+
+app = Flask(__name__)
+
+def get_db_connection():
+ """Create a database connection"""
+ conn = sqlite3.connect(DB_FILE)
+ conn.row_factory = sqlite3.Row # This allows us to access columns by name
+ return conn
+
+def get_counter_data():
+ """Get all counter data from the database"""
+ conn = get_db_connection()
+ cursor = conn.cursor()
+
+ # Get all records ordered by date descending
+ cursor.execute("""
+ SELECT id, camera_name, date, counter_value
+ FROM counter_data
+ ORDER BY date DESC
+ """)
+
+ rows = cursor.fetchall()
+ conn.close()
+
+ # Convert to list of dictionaries
+ data = []
+ for row in rows:
+ data.append({
+ 'id': row['id'],
+ 'camera_name': row['camera_name'],
+ 'date': row['date'],
+ 'counter_value': row['counter_value']
+ })
+
+ return data
+
+def get_counter_summary():
+ """Get summary of counter data grouped by camera"""
+ conn = get_db_connection()
+ cursor = conn.cursor()
+
+ # Get latest counter value for each camera
+ cursor.execute("""
+ SELECT camera_name, MAX(date) as latest_date, counter_value
+ FROM counter_data
+ GROUP BY camera_name
+ ORDER BY latest_date DESC
+ """)
+
+ rows = cursor.fetchall()
+ conn.close()
+
+ # Convert to list of dictionaries
+ data = []
+ for row in rows:
+ data.append({
+ 'camera_name': row['camera_name'],
+ 'latest_date': row['latest_date'],
+ 'counter_value': row['counter_value']
+ })
+
+ return data
+
+def get_pivoted_data():
+ """Get counter data pivoted by camera_name (rows) and date (columns)"""
+ conn = get_db_connection()
+ cursor = conn.cursor()
+
+ # Get all records ordered by date DESC (latest first)
+ cursor.execute("""
+ SELECT camera_name, date, counter_value
+ FROM counter_data
+ ORDER BY date DESC
+ """)
+
+ rows = cursor.fetchall()
+ conn.close()
+
+ # Group data by camera and date
+ pivoted_data = defaultdict(lambda: defaultdict(int))
+ dates = set()
+ cameras = set()
+
+ for row in rows:
+ camera_name = row['camera_name']
+ date = row['date'][:10] # Extract just the date part (YYYY-MM-DD)
+ counter_value = row['counter_value']
+
+ pivoted_data[camera_name][date] = counter_value
+ dates.add(date)
+ cameras.add(camera_name)
+
+ # Convert sets to sorted lists (sort dates in reverse order - latest first)
+ sorted_dates = sorted(dates, reverse=True)
+ sorted_cameras = sorted(cameras)
+
+ # Create matrix format
+ matrix = []
+ for camera in sorted_cameras:
+ row = {'camera_name': camera}
+ for date in sorted_dates:
+ row[date] = pivoted_data[camera][date]
+ matrix.append(row)
+
+ return {
+ 'matrix': matrix,
+ 'dates': sorted_dates,
+ 'cameras': sorted_cameras
+ }
+
+@app.route('/')
+def index():
+ """Main page showing counter data"""
+ counter_data = get_counter_data()
+ summary_data = get_counter_summary()
+ pivoted_data = get_pivoted_data()
+
+ # Add current datetime to context
+ current_time = datetime.now()
+
+ return render_template('index.html',
+ counter_data=counter_data,
+ summary_data=summary_data,
+ pivoted_data=pivoted_data,
+ current_time=current_time)
+
+@app.route('/api/data')
+def api_data():
+ """API endpoint to get counter data as JSON"""
+ counter_data = get_counter_data()
+ return jsonify(counter_data)
+
+@app.route('/api/summary')
+def api_summary():
+ """API endpoint to get counter summary as JSON"""
+ summary_data = get_counter_summary()
+ return jsonify(summary_data)
+
+@app.route('/api/pivoted')
+def api_pivoted():
+ """API endpoint to get pivoted counter data as JSON"""
+ pivoted_data = get_pivoted_data()
+ return jsonify(pivoted_data)
+
+if __name__ == '__main__':
+
+ # Create database directory if it doesn't exist
+ os.makedirs(os.path.dirname(DB_FILE), exist_ok=True)
+
+ # Initialize the database if needed
+ conn = sqlite3.connect(DB_FILE)
+ cursor = conn.cursor()
+
+ cursor.execute("""
+ CREATE TABLE IF NOT EXISTS counter_data (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ camera_name TEXT NOT NULL,
+ date TIMESTAMP NOT NULL,
+ counter_value INTEGER NOT NULL
+ )
+ """)
+
+ conn.commit()
+ conn.close()
+
+ app.run(host='0.0.0.0', port=8899, debug=True)