Files
location_managemet/run.py
ske087 90cbf4e1f0 Add Layouts module with Konva.js builder; smart offline polling; UI improvements
- Move board cards from dashboard to top of boards list page
- Fix Werkzeug duplicate polling (WERKZEUG_RUN_MAIN guard)
- Smart offline polling: fast loop for online boards, slow recheck for offline
- Add manual ping endpoint POST /api/boards/<id>/ping
- Add spin animation CSS for ping button

Layouts module (new):
- app/models/layout.py: Layout model (canvas_json, thumbnail_b64)
- app/routes/layouts.py: 5 routes (list, create, builder, save, delete)
- app/templates/layouts/: list and builder templates
- app/static/js/layout_builder.js: full Konva.js builder engine
- app/static/vendor/konva/: vendored Konva.js 9
- Structure mode: wall, room, door, window, fence, text shapes
- Devices mode: drag relay/input/Sonoff channels onto canvas
- Live view mode: click relays/Sonoff to toggle, socket.io state updates
- Device selection: click to select, remove individual device, Delete key
- Fix door/Arc size persistence across save/reload (outerRadius, scaleX/Y)
- Fix Sonoff devices missing from palette (add makeSonoffChip function)
2026-02-27 13:34:44 +02:00

59 lines
1.9 KiB
Python

"""Application entry point.
Run with:
python run.py
Or for production:
gunicorn -w 1 -k eventlet "run:create_socketio_app()"
"""
import os
import threading
import time
from app import create_app, socketio
from app.services.board_service import poll_online_boards, recheck_offline_boards
app = create_app(os.environ.get("FLASK_ENV", "development"))
def _online_poller():
"""Fast loop — polls only online boards every BOARD_POLL_INTERVAL seconds."""
interval = app.config.get("BOARD_POLL_INTERVAL", 10)
while True:
try:
poll_online_boards(app)
except Exception as exc:
app.logger.warning("Online poller error: %s", exc)
time.sleep(interval)
def _offline_recheck_poller():
"""Slow loop — probes offline boards every OFFLINE_RECHECK_INTERVAL seconds.
Waits one full interval before the first check so startup is clean.
"""
interval = app.config.get("OFFLINE_RECHECK_INTERVAL", 60)
while True:
time.sleep(interval) # wait first, then check
try:
recheck_offline_boards(app)
except Exception as exc:
app.logger.warning("Offline recheck error: %s", exc)
def create_socketio_app():
"""WSGI callable for gunicorn / production."""
return socketio.middleware(app)
if __name__ == "__main__":
# Werkzeug debug-reloader starts two processes; only start the poller in
# the actual worker (WERKZEUG_RUN_MAIN=true) to avoid duplicate polling.
# In non-debug mode (WERKZEUG_RUN_MAIN is unset) we always start it.
if not app.debug or os.environ.get("WERKZEUG_RUN_MAIN") == "true":
threading.Thread(target=_online_poller, daemon=True).start()
threading.Thread(target=_offline_recheck_poller, daemon=True).start()
port = int(os.environ.get("PORT", 5000))
socketio.run(app, host="0.0.0.0", port=port, debug=app.debug, allow_unsafe_werkzeug=True)