Table of Contents

Configuration

WebConfig.py

WebConfig.py
# WebConfig.py
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
 
def on_tickets_updated(ui, count):
    """Called after each successful ticket update — notifies the frontend."""
    now = datetime.now(ZoneInfo("Europe/Zurich")).strftime("%H:%M:%S")
    ui.send_message("tickets_updated", {"count": count, "time": now})
 
def init_index_interface(ui):
    """
    Registers the bridge between index.html and Python logic.
    """
 
    def handle_status_request(client_id, data):
        """
        Triggered when the frontend sends 'get_api_status'.
        Checks readiness and sends back 'api_status_data'.
        """
 
        from Tools import check_api_readiness
 
        is_ready = check_api_readiness()
 
        print(f"DEBUG: API Readiness requested by {client_id}. Result: {is_ready}")
 
        # Send the response back to the UI
        ui.send_message("api_status_data", {"ready": is_ready})
 
    # Register the listener
    ui.on_message("get_api_status", handle_status_request)
 
    def handle_get_arduino_config(client_id, data):
        from PersistentData import get_config
        ui.send_message("arduino_config", {
            "lcd_backlight":   int(get_config("arduino_lcd_backlight")   or 1),
            "temp_brightness": int(get_config("arduino_temp_brightness") or 7),
            "humi_brightness": int(get_config("arduino_humi_brightness") or 4),
            "co2_brightness":  int(get_config("arduino_co2_brightness")  or 2),
            "ring_brightness": int(get_config("arduino_ring_brightness") or 20),
        })
 
    def handle_save_arduino_config(client_id, data):
        from PersistentData import save_config
        try:
            for key in ["lcd_backlight", "temp_brightness", "humi_brightness",
                        "co2_brightness", "ring_brightness"]:
                if data.get(key) is not None:
                    save_config(f"arduino_{key}", data[key])
            ui.send_message("arduino_config_saved", {"ok": True})
        except Exception as e:
            print(f"ERROR saving arduino config: {e}")
            ui.send_message("arduino_config_saved", {"ok": False})
 
    ui.on_message("get_arduino_config",  handle_get_arduino_config)
    ui.on_message("save_arduino_config", handle_save_arduino_config)
 
    def handle_cleanup_sensor_history(client_id, data):
        try:
            import os, PersistentData as PD
            from influxdb_client import InfluxDBClient
            url    = os.environ.get("INFLUXDB_URL",   "http://dbstorage-influx:8086")
            token  = PD.get_config("influxdbToken") or os.environ.get("INFLUXDB_TOKEN", "")
            org    = os.environ.get("INFLUXDB_ORG",   "arduino")
            bucket = os.environ.get("INFLUXDB_BUCKET","arduinostorage")
            client = InfluxDBClient(url=url, token=token, org=org)
            delete_api = client.delete_api()
            start = "1970-01-01T00:00:00Z"
            stop  = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
            delete_api.delete(start, stop, "", bucket=bucket, org=org)
            client.close()
            print("INFO: Sensor history cleared.")
            ui.send_message("cleanup_done", {"ok": True,  "label": "Sensor history"})
        except Exception as e:
            print(f"ERROR clearing sensor history: {e}")
            ui.send_message("cleanup_done", {"ok": False, "label": "Sensor history"})
 
    def handle_cleanup_ticket_history(client_id, data):
        try:
            import PersistentData
            PersistentData.db.execute_sql("DELETE FROM history")
            print("INFO: Ticket history cleared.")
            ui.send_message("cleanup_done", {"ok": True,  "label": "Tickets history"})
        except Exception as e:
            print(f"ERROR clearing ticket history: {e}")
            ui.send_message("cleanup_done", {"ok": False, "label": "Tickets history"})
 
    ui.on_message("cleanup_sensor_history", handle_cleanup_sensor_history)
    ui.on_message("cleanup_ticket_history", handle_cleanup_ticket_history)

Config.html

config.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>P1 Notifications 4 Cockpit ITSM - Configuration</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    <link rel="icon" type="image/x-icon" href="img/favicon.ico">
</head>
<body>
    <div class="container">
        <header>
            <h1>P1 Notifications 4 Cockpit ITSM</h1>
        </header>
 
        <div class="button-group" style="flex-direction: column;">
            <a href="CockpitTSM.html" class="btn-secondary" style="width:100%;">
                <img src="img/cloud-filled-gear.svg" alt="" class="btn-icon">
                API Configuration
            </a>
 
            <button id="btnOrgs" class="btn-secondary" disabled style="opacity: 0.5; cursor: not-allowed; width: 100%;">
                <img src="img/company-building-filled.svg" alt="" class="btn-icon">
                Organizations
            </button>
 
            <button id="btnTeams" class="btn-secondary" disabled style="opacity: 0.5; cursor: not-allowed; width: 100%;">
                <img src="img/teams.svg" alt="" class="btn-icon">
                Teams
            </button>
 
            <button id="btnStatus" class="btn-secondary" disabled style="opacity: 0.5; cursor: not-allowed; width: 100%;">
                <img src="img/monitoring.svg" alt="" class="btn-icon">
                Ticket Status
            </button>
 
            <button id="btnPriority" class="btn-secondary" disabled style="opacity: 0.5; cursor: not-allowed; width: 100%;">
                <img src="img/traffic-light-orange.svg" alt="" class="btn-icon">
                Ticket Priority
            </button>
 
            <button id="btnCriticity" class="btn-secondary" disabled style="opacity: 0.5; cursor: not-allowed; width: 100%;">
                <img src="img/time-late-task.svg" alt="" class="btn-icon">
                Ticket Criticity
            </button>
 
            <button id="btnArduino" class="btn-secondary" disabled style="opacity: 0.5; cursor: not-allowed; width: 100%;">
                <img src="img/arduino.svg" alt="" class="btn-icon">
                Arduino
            </button>
            <a href="index.html" class="btn-secondary" style="width:100%; margin-top: 0.5rem;">
                <img src="img/dashboard.svg" alt="" class="btn-icon">Back to Dashboard
            </a>
        </div>
 
        <div id="statusMessage" class="status-message" style="color: #bb86fc; margin-top: 1.5rem;">
            Connecting...
        </div>
    </div>
    <script src="libs/socket.io.min.js"></script>
    <script src="app_config.js"></script>
</body>
</html>

app_config.js

app_config.js
// app_config.js
 
const socket = io();
 
const btnOrgs     = document.getElementById('btnOrgs');
const btnTeams    = document.getElementById('btnTeams');
const btnStatus   = document.getElementById('btnStatus');
const btnPriority = document.getElementById('btnPriority');
const btnArduino  = document.getElementById('btnArduino');
const statusMessage = document.getElementById('statusMessage');
let statusReceived = false;
 
// Arduino does not depend on the API — always enabled
btnArduino.disabled = false;
btnArduino.style.opacity = "1";
btnArduino.style.cursor = "pointer";
btnArduino.onclick = () => { window.location.href = 'Arduino.html'; };
 
// Listen for the status data from WebIndex.py
socket.on("api_status_data", (data) => {
  console.log("Status received:", data);
  statusReceived = true; 
 
  if (data && data.ready) {
    // API is Ready
    btnOrgs.disabled = false;
    btnOrgs.style.opacity = "1";
    btnOrgs.style.cursor = "pointer";
    btnOrgs.onclick = () => { window.location.href = 'Organizations.html'; };
 
    btnTeams.disabled = false;
    btnTeams.style.opacity = "1";
    btnTeams.style.cursor = "pointer";
    btnTeams.onclick = () => { window.location.href = 'Teams.html'; };
 
    btnStatus.disabled = false;
    btnStatus.style.opacity = "1";
    btnStatus.style.cursor = "pointer";
    btnStatus.onclick = () => { window.location.href = 'Status.html'; };
 
    btnPriority.disabled = false;
    btnPriority.style.opacity = "1";
    btnPriority.style.cursor = "pointer";
    btnPriority.onclick = () => { window.location.href = 'Priority.html'; };
 
    btnCriticity.disabled = false;
    btnCriticity.style.opacity = "1";
    btnCriticity.style.cursor = "pointer";
    btnCriticity.onclick = () => { window.location.href = 'Criticity.html'; };
 
    statusMessage.textContent = "";
  } else {
    // API not configured
    btnOrgs.disabled = true;
    btnOrgs.style.opacity = "0.5";
    btnOrgs.style.cursor = "not-allowed";
 
    btnTeams.disabled = true;
    btnTeams.style.opacity = "0.5";
    btnTeams.style.cursor = "not-allowed";
 
    btnStatus.disabled = true;
    btnStatus.style.opacity = "0.5";
    btnStatus.style.cursor = "not-allowed";
 
    btnPriority.disabled = true;
    btnPriority.style.opacity = "0.5";
    btnPriority.style.cursor = "not-allowed";
 
    btnCriticity.disabled = true;
    btnCriticity.style.opacity = "0.5";
    btnCriticity.style.cursor = "not-allowed";
 
    statusMessage.textContent = "Please configure API";
  }
});
 
// Retry logic: Ask every second until we get an answer
const checkInterval = setInterval(() => {
  if (!statusReceived) {
    console.log("Probing API status...");
    socket.emit("get_api_status", {});
  } else {
    clearInterval(checkInterval);
  }
}, 1000);
 
// Also try once immediately on load
document.addEventListener('DOMContentLoaded', () => {
  socket.emit("get_api_status", {});
});