Add config UI interface and update app.py with config card functionality
- Copied config.py with FreeSimpleGUI configuration interface to root folder - Added load_config() function to launch config UI when card 12886709 is inserted - Config UI allows setting hostname and work table (Loc De Munca) - Automatic printer configuration and hostname updates - System reboot after configuration changes - Added config.py to version control
This commit is contained in:
@@ -195,6 +195,32 @@ def post_backup_data():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error posting backup data: {e}")
|
logging.error(f"Error posting backup data: {e}")
|
||||||
|
|
||||||
|
def load_config():
|
||||||
|
"""Launch configuration UI when config card is inserted (card ID: 12886709)"""
|
||||||
|
try:
|
||||||
|
config_path = "./config.py"
|
||||||
|
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
logging.info("🔧 Launching configuration interface...")
|
||||||
|
print("🔧 Launching configuration interface...")
|
||||||
|
|
||||||
|
# Launch config.py as a subprocess
|
||||||
|
subprocess.Popen([sys.executable, config_path],
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
|
logging.info("✓ Configuration UI launched successfully")
|
||||||
|
print("✓ Configuration UI launched successfully")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logging.error("Config file not found at ./config.py")
|
||||||
|
print("✗ Config file not found at ./config.py")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error launching configuration: {e}")
|
||||||
|
print(f"✗ Error launching configuration: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# RFID READER - Background Thread
|
# RFID READER - Background Thread
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -256,10 +282,12 @@ class RFIDReader(rdm6300.BaseReader):
|
|||||||
"""Detect card insertion - just set flag"""
|
"""Detect card insertion - just set flag"""
|
||||||
card_id = card.value
|
card_id = card.value
|
||||||
|
|
||||||
# Special card: device config card (ignore)
|
# Special card: device config card
|
||||||
if card_id == 12886709:
|
if card_id == 12886709:
|
||||||
logging.info(f"🔴 CONFIG CARD {card_id} detected (ignored)")
|
logging.info(f"🔴 CONFIG CARD {card_id} detected - Loading configuration")
|
||||||
print(f"🔴 CONFIG CARD {card_id} detected (ignored)")
|
print(f"🔴 CONFIG CARD {card_id} detected - Loading configuration")
|
||||||
|
# Call config loading function
|
||||||
|
load_config()
|
||||||
return
|
return
|
||||||
|
|
||||||
# IMMEDIATE LED feedback (BEFORE flag, for instant response)
|
# IMMEDIATE LED feedback (BEFORE flag, for instant response)
|
||||||
@@ -305,19 +333,23 @@ def process_card_events(hostname, device_ip):
|
|||||||
if card_id is not None:
|
if card_id is not None:
|
||||||
logging.info(f"[Main] Processing CARD INSERTED: {card_id}")
|
logging.info(f"[Main] Processing CARD INSERTED: {card_id}")
|
||||||
|
|
||||||
# Build API URL (1 = ON/inserted)
|
# Skip posting to Harting API if device is not configured
|
||||||
url = f"{HARTING_API_BASE}/{name}/{card_id}/1/{timestamp}"
|
if name != "noconfig":
|
||||||
|
# Build API URL (1 = ON/inserted)
|
||||||
# Try to post
|
url = f"{HARTING_API_BASE}/{name}/{card_id}/1/{timestamp}"
|
||||||
if post_to_harting(url):
|
|
||||||
logging.info(f"✓ Card event posted to API: {card_id}")
|
# Try to post
|
||||||
|
if post_to_harting(url):
|
||||||
|
logging.info(f"✓ Card event posted to API: {card_id}")
|
||||||
|
else:
|
||||||
|
logging.warning(f"✗ Offline: Saving card {card_id} to backup")
|
||||||
|
try:
|
||||||
|
with open(TAG_FILE, "a") as f:
|
||||||
|
f.write(url + "\n")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to save backup: {e}")
|
||||||
else:
|
else:
|
||||||
logging.warning(f"✗ Offline: Saving card {card_id} to backup")
|
logging.debug(f"Device not configured (noconfig). Skipping API post for card {card_id}")
|
||||||
try:
|
|
||||||
with open(TAG_FILE, "a") as f:
|
|
||||||
f.write(url + "\n")
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Failed to save backup: {e}")
|
|
||||||
|
|
||||||
# ALWAYS send log to monitoring server (regardless of API post result)
|
# ALWAYS send log to monitoring server (regardless of API post result)
|
||||||
send_log_to_server(f"Card {card_id} inserted", hostname, device_ip, name)
|
send_log_to_server(f"Card {card_id} inserted", hostname, device_ip, name)
|
||||||
@@ -327,19 +359,23 @@ def process_card_events(hostname, device_ip):
|
|||||||
if card_id is not None:
|
if card_id is not None:
|
||||||
logging.info(f"[Main] Processing CARD REMOVED: {card_id}")
|
logging.info(f"[Main] Processing CARD REMOVED: {card_id}")
|
||||||
|
|
||||||
# Build API URL (0 = OFF/removed)
|
# Skip posting to Harting API if device is not configured
|
||||||
url = f"{HARTING_API_BASE}/{name}/{card_id}/0/{timestamp}"
|
if name != "noconfig":
|
||||||
|
# Build API URL (0 = OFF/removed)
|
||||||
# Try to post
|
url = f"{HARTING_API_BASE}/{name}/{card_id}/0/{timestamp}"
|
||||||
if post_to_harting(url):
|
|
||||||
logging.info(f"✓ Card event posted to API: {card_id}")
|
# Try to post
|
||||||
|
if post_to_harting(url):
|
||||||
|
logging.info(f"✓ Card event posted to API: {card_id}")
|
||||||
|
else:
|
||||||
|
logging.warning(f"✗ Offline: Saving card {card_id} to backup")
|
||||||
|
try:
|
||||||
|
with open(TAG_FILE, "a") as f:
|
||||||
|
f.write(url + "\n")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to save backup: {e}")
|
||||||
else:
|
else:
|
||||||
logging.warning(f"✗ Offline: Saving card {card_id} to backup")
|
logging.debug(f"Device not configured (noconfig). Skipping API post for card {card_id}")
|
||||||
try:
|
|
||||||
with open(TAG_FILE, "a") as f:
|
|
||||||
f.write(url + "\n")
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Failed to save backup: {e}")
|
|
||||||
|
|
||||||
# ALWAYS send log to monitoring server (regardless of API post result)
|
# ALWAYS send log to monitoring server (regardless of API post result)
|
||||||
send_log_to_server(f"Card {card_id} removed", hostname, device_ip, name)
|
send_log_to_server(f"Card {card_id} removed", hostname, device_ip, name)
|
||||||
@@ -495,6 +531,73 @@ def cleanup_old_logs(hostname, device_ip, name):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error cleaning up logs: {e}")
|
logging.error(f"Error cleaning up logs: {e}")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# CHROMIUM LAUNCHER
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
def launch_chromium(name):
|
||||||
|
"""
|
||||||
|
Launch Chromium with either production URL or local fallback page
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Debug logging
|
||||||
|
print(f"DEBUG: launch_chromium called with name='{name}'")
|
||||||
|
print(f"DEBUG: name type={type(name)}, len={len(name)}")
|
||||||
|
print(f"DEBUG: name != 'noconfig' = {name != 'noconfig'}")
|
||||||
|
logging.debug(f"DEBUG: launch_chromium called with name='{name}' (type={type(name).__name__}, len={len(name)})")
|
||||||
|
|
||||||
|
# Determine which URL to use based on device configuration
|
||||||
|
if name != "noconfig":
|
||||||
|
# Device is configured - use production URL
|
||||||
|
url = "http://10.76.140.17/iweb_v2/index.php/traceability/production"
|
||||||
|
print(f"Device configured as '{name}'. Launching production URL: {url}")
|
||||||
|
logging.info(f"Launching Chromium with production URL for device: {name}")
|
||||||
|
|
||||||
|
# Launch Chromium with production URL
|
||||||
|
print("Starting Chromium with production URL...")
|
||||||
|
subprocess.Popen(
|
||||||
|
["chromium", "--test-type", "--noerrors", "--kiosk", "--start-fullscreen",
|
||||||
|
"--unsafely-treat-insecure-origin-as-secure=http://10.76.140.17", url],
|
||||||
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL,
|
||||||
|
start_new_session=True
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Device not configured - use local HTML file
|
||||||
|
print(f"Device NOT configured (name='noconfig'). Using local HTML.")
|
||||||
|
local_html_dir = os.path.join(DATA_DIR, "html")
|
||||||
|
local_html_file = os.path.join(local_html_dir, "Screen.html")
|
||||||
|
|
||||||
|
# Create directory if it doesn't exist
|
||||||
|
os.makedirs(local_html_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Check if local HTML file exists
|
||||||
|
if not os.path.exists(local_html_file):
|
||||||
|
print(f"Warning: Local HTML file not found at {local_html_file}")
|
||||||
|
print(f"Please create the file or copy it from the data/html directory")
|
||||||
|
logging.warning(f"Local HTML file not found: {local_html_file}")
|
||||||
|
|
||||||
|
# Convert to file:// URL for local file
|
||||||
|
abs_path = os.path.abspath(local_html_file)
|
||||||
|
url = f"file://{abs_path}"
|
||||||
|
print(f"Device not configured. Launching local fallback page: {url}")
|
||||||
|
logging.info(f"Loading Screen.html from: {abs_path}")
|
||||||
|
|
||||||
|
# Launch Chromium with local file - different flags for file:// URLs
|
||||||
|
print("Starting Chromium with local HTML file...")
|
||||||
|
subprocess.Popen(
|
||||||
|
["chromium", "--test-type", "--noerrors", "--kiosk", "--start-fullscreen",
|
||||||
|
"--no-first-run", "--no-default-browser-check", url],
|
||||||
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL,
|
||||||
|
start_new_session=True
|
||||||
|
)
|
||||||
|
|
||||||
|
print("✓ Chromium launched successfully")
|
||||||
|
logging.info("Chromium launched successfully")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to launch Chromium: {e}")
|
||||||
|
logging.error(f"Failed to launch Chromium: {e}")
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# MAIN APPLICATION
|
# MAIN APPLICATION
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -550,7 +653,11 @@ def main():
|
|||||||
wifi_thread.start()
|
wifi_thread.start()
|
||||||
print("✓ WiFi monitor started")
|
print("✓ WiFi monitor started")
|
||||||
|
|
||||||
# Application ready
|
# Launch Chromium browser
|
||||||
|
print("\nInitializing Chromium launcher...")
|
||||||
|
time.sleep(2) # Give system time to stabilize
|
||||||
|
launch_chromium(read_idmasa())
|
||||||
|
print()
|
||||||
logging.info("RFID Client operational")
|
logging.info("RFID Client operational")
|
||||||
send_log_to_server("RFID Client operational", hostname, device_ip, read_idmasa())
|
send_log_to_server("RFID Client operational", hostname, device_ip, read_idmasa())
|
||||||
print("✓ RFID Client operational - waiting for cards...")
|
print("✓ RFID Client operational - waiting for cards...")
|
||||||
205
config.py
Normal file
205
config.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
# config py este gandit pentru a verifica configurarile raspberiului
|
||||||
|
# verifica hostname-ul si il afiseaza
|
||||||
|
# verifica ce nume are masa si o afiseaza
|
||||||
|
# verifica daca masa este configurata cu sistem de prezenta operator
|
||||||
|
# verifica daca imprimanta este instalata corespunzator
|
||||||
|
|
||||||
|
import os, time, socket, cups, subprocess
|
||||||
|
import FreeSimpleGUI as psg
|
||||||
|
import FreeSimpleGUI as sg
|
||||||
|
from multiprocessing import Process
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# import socket
|
||||||
|
host = socket.gethostname() # luam numele de host
|
||||||
|
def set_printer(): # importam codul python pentru printer
|
||||||
|
print("Cheking printer")
|
||||||
|
# acest segment acceseaza fisierul local idmas.txt si verifica ce informatii sunt acolo
|
||||||
|
# in mod normal acolo salvam numele mesei care trebuie sa corespunda cu numele imprimantei
|
||||||
|
f = open("./data/idmasa.txt","r") # deschid fisierul in care am salvat numele printerului
|
||||||
|
test = f.readlines() # citesc toate liniile
|
||||||
|
f.close()
|
||||||
|
# in cazul in care avem fisier corupt il resetam la original
|
||||||
|
try:
|
||||||
|
idmasa = test[0]
|
||||||
|
|
||||||
|
except IndexError:
|
||||||
|
idmasa = "0"
|
||||||
|
print(idmasa)
|
||||||
|
# citim lista de printere disponibila
|
||||||
|
conn = cups.Connection ()
|
||||||
|
printers = conn.getPrinters ()
|
||||||
|
printer_stat=0
|
||||||
|
for printer in printers:
|
||||||
|
print (printer, printers[printer]["device-uri"])
|
||||||
|
if printer == idmasa:
|
||||||
|
printer_stat = 1
|
||||||
|
|
||||||
|
|
||||||
|
if printer_stat == 1:
|
||||||
|
print("Printer is Ok")
|
||||||
|
else:
|
||||||
|
print("Printer is not ok")
|
||||||
|
p_Name = idmasa
|
||||||
|
print("Installing the new printer")
|
||||||
|
time.sleep(2)
|
||||||
|
cmd = "sudo /usr/sbin/lpadmin -p "+idmasa+" -E -v usb://CITIZEN/CT-S310II?serial=00000000 -m CTS310II.ppd"
|
||||||
|
os.popen(cmd)
|
||||||
|
time.sleep(2)
|
||||||
|
print("Printer Was Installed")
|
||||||
|
conn = cups.Connection()
|
||||||
|
printers = conn.getPrinters()
|
||||||
|
for printer in printers:
|
||||||
|
print(printer, printers[printer]["device-uri"])
|
||||||
|
time.sleep(1)
|
||||||
|
print("Printerwas seted to "+idmasa+"")
|
||||||
|
print("Test printer App Closed")
|
||||||
|
# partea acesata se ocupa de verificarea existentei celor doua fisiere pentru a nu avea erori
|
||||||
|
# verificam daca exista fisierul care identifica masa
|
||||||
|
path = './data/idmasa.txt'
|
||||||
|
isFile = os.path.isfile(path) #verifica existenta fisierului prin bolean Tru/false
|
||||||
|
|
||||||
|
if not isFile:
|
||||||
|
# print(path)# nu se face nimic pentru ca exista fisierul
|
||||||
|
|
||||||
|
fp = open("./data/idmasa.txt", 'w') # cream fisier
|
||||||
|
fp.write('noconfig') # scriem in fisier prima line pentru a avea un punct de pornire
|
||||||
|
fp.close() # inchidem fisierul
|
||||||
|
|
||||||
|
# verificam fisierul de prezenta pe baza acestuia stim daca locul de munca este configurat cu card de prezenta sau nu
|
||||||
|
path1 = './data/idmasa.txt' #verificare existenta al doilea fisier
|
||||||
|
isFile = os.path.isfile(path1)# verifica existenta fisierului
|
||||||
|
|
||||||
|
#urmeaza sa citim fisierele pentru a crea cateva variabile
|
||||||
|
# prima variabila este idmasa
|
||||||
|
f = open("./data/idmasa.txt","r") # deschid fisierul
|
||||||
|
name = f.readlines() # citesc toate liniile
|
||||||
|
f.close() # inchid fisierul
|
||||||
|
try:
|
||||||
|
idmasa = name[0]# se verifica daca exista informatie in text
|
||||||
|
|
||||||
|
except IndexError:
|
||||||
|
idmasa = "noconfig"# daca nu exista informatie in text setam variabila
|
||||||
|
|
||||||
|
|
||||||
|
n_config = 0
|
||||||
|
#incepem sa definim primele functii din configurare
|
||||||
|
def notokfunction(): # este functie pentru butonul cancel din formular
|
||||||
|
global n_config
|
||||||
|
msg1 = "Id masa a fost actualizat la: "+ idmasa +"" ## pregatim mesajul pentru fereastra pop up
|
||||||
|
n_config = 1
|
||||||
|
msg2 = "Slotul Pentru cartela este configurat by default" # pregatim mesajul pentru fereastra pop up
|
||||||
|
layout = [[sg.Text(msg1)], [sg.Text(msg2)], [sg.Button("Ok")]]
|
||||||
|
window = sg.Window("Configurari", layout)
|
||||||
|
while True:
|
||||||
|
event, values = window.read()
|
||||||
|
|
||||||
|
if event == "Ok" or event == sg.WIN_CLOSED:
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
window.close()
|
||||||
|
#am inchis functia notok
|
||||||
|
|
||||||
|
#functia pentru butonul ok din formular
|
||||||
|
def okfunction():
|
||||||
|
global n_config
|
||||||
|
if idmasa == config1: # variabila config 1 este preluata din formular
|
||||||
|
msg1 = "Masa este setat corect: "+ idmasa +"" # se printeaza mesaj ca nu se actualizeaza id de masa
|
||||||
|
# print(msg1)
|
||||||
|
else:
|
||||||
|
f = open("./data/idmasa.txt","w") # deschidem fisierul config in mod scriere
|
||||||
|
L = config1
|
||||||
|
f.write(L) # actualizam linia cu noua valuare din config
|
||||||
|
f.close() # inchidem fisierul
|
||||||
|
msg1 = "Id masa a fost actualizat la: "+ config1 +"" # pregatim mesajul pentru fereastra pop up
|
||||||
|
n_config = 0
|
||||||
|
#
|
||||||
|
|
||||||
|
# definim fereastra pentru ok asemena cu functia notok
|
||||||
|
layout = [[sg.Text(msg1)], [sg.Output(size=(40, 15))], [sg.Button("Ok")]]
|
||||||
|
|
||||||
|
window = sg.Window("Configurari", layout)
|
||||||
|
while True:
|
||||||
|
event, values = window.read()
|
||||||
|
# End program if user closes window or
|
||||||
|
# presses the OK button
|
||||||
|
if event == "Ok" or event == sg.WIN_CLOSED:
|
||||||
|
|
||||||
|
break
|
||||||
|
if nook == 1:
|
||||||
|
notokfunction()
|
||||||
|
n_config = 1
|
||||||
|
time.sleep(2)
|
||||||
|
#asteptam 10 secunde si pornim functia de setare printer
|
||||||
|
set_printer()
|
||||||
|
#verificam daca hostul corespunde cu ce este in formular
|
||||||
|
time.sleep(2)
|
||||||
|
if host == host_conf:
|
||||||
|
print("Host name ok")
|
||||||
|
else:
|
||||||
|
print("Host name not ok")
|
||||||
|
time.sleep(2)
|
||||||
|
print("Update Hostname" )
|
||||||
|
cmd = "sudo hostnamectl set-hostname "+host_conf+"" # comanda sa schimbam hostnameul
|
||||||
|
os.popen(cmd)
|
||||||
|
print("Os hostname updated")
|
||||||
|
time.sleep(2)
|
||||||
|
print("System will reboot in 5 seconds")
|
||||||
|
time.sleep(1)
|
||||||
|
print("System will reboot in 4 seconds")
|
||||||
|
time.sleep(1)
|
||||||
|
print("System will reboot in 3 seconds")
|
||||||
|
time.sleep(1)
|
||||||
|
print("System will reboot in 2 seconds")
|
||||||
|
time.sleep(1)
|
||||||
|
print("System will reboot in 1 seconds")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.close()
|
||||||
|
# incepem initializarea feresteri ptrincipale gui
|
||||||
|
|
||||||
|
sg.theme('dark grey 9') #alegem tema dark grey
|
||||||
|
psg.set_options(font=('Arial Bold', 16)) # setam fontul
|
||||||
|
#setarile de layout
|
||||||
|
layout = [
|
||||||
|
[sg.Text('Host_Name', size=(20,1)),sg.InputText(default_text= ""+host+"" , enable_events=False)],
|
||||||
|
[sg.Text('Loc De Munca', size=(20,1)),sg.InputText(default_text=""+idmasa+"", enable_events=False)],
|
||||||
|
|
||||||
|
[sg.Button('Ok'), sg.Button('Cancel')]
|
||||||
|
]
|
||||||
|
# setam window
|
||||||
|
window = psg.Window('Form', layout, size=(800,190),finalize=True)
|
||||||
|
# citim si configuram widgetul pentru butoanele 1 si 0 din randul
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
nook = 0 # cream o variabila care sa ne spuna daca a fost setao butonul ok sau nu
|
||||||
|
event, values = window.read() # citim valorile intr-o lista numita values
|
||||||
|
host_conf= values[0] # atribuim primul item din lista variabilei Host config
|
||||||
|
# aceasta variabila o vom folosi pentru a scrie sa nu noul hostname
|
||||||
|
print(host_conf)
|
||||||
|
if event == sg.WIN_CLOSED or event == 'Cancel':
|
||||||
|
nook = 1 # daca se da cancel setam variabila nook la 1
|
||||||
|
n_config = 1 # setam variabila n_config la 1
|
||||||
|
break
|
||||||
|
config1 = values[1] # atribuim lui config 1 valuarea din campul Loc de munca care a fost scris cu Id masa
|
||||||
|
|
||||||
|
|
||||||
|
# pornim functi care scrie valorile config in fisiere ok function
|
||||||
|
okfunction()
|
||||||
|
# si inchidem formularul
|
||||||
|
|
||||||
|
# semnalam ca s-a terminat afisarea formularului
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
#inchidem formularul
|
||||||
|
window.close()
|
||||||
|
# daca variabila nook este 1
|
||||||
|
time.sleep(2)
|
||||||
|
if n_config == 0:
|
||||||
|
os.system("sudo reboot now")
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
RPI-Device
|
RPI-testDevice
|
||||||
192.168.1.104
|
192.168.1.104
|
||||||
|
|||||||
69
data/html/Screen.html
Executable file
69
data/html/Screen.html
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Device Not Configured</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
#container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
#fallback {
|
||||||
|
display: none;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<img id="mainImage" src="file:///home/pi/Desktop/Prezenta/data/html/harting_background.jpg" alt="Harting Module" />
|
||||||
|
<div id="fallback">
|
||||||
|
<h1>Device Not Configured</h1>
|
||||||
|
<p>Please scan the configuration RFID card</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('mainImage').onerror = function() {
|
||||||
|
console.error('Image failed to load, showing fallback');
|
||||||
|
document.getElementById('mainImage').style.display = 'none';
|
||||||
|
document.getElementById('fallback').style.display = 'block';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Log when image loads successfully
|
||||||
|
document.getElementById('mainImage').onload = function() {
|
||||||
|
console.log('Image loaded successfully');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
data/html/harting_background.jpg
Normal file
BIN
data/html/harting_background.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 342 KiB |
125
data/html/index.html
Normal file
125
data/html/index.html
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Device Configuration Required</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #000;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #000;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #000;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
padding: 20px;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #ccc;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="image-wrapper">
|
||||||
|
<img src="file:///home/pi/Desktop/Prezenta/data/html/harting_background.jpg" alt="Harting Module" onerror="handleImageError()">
|
||||||
|
</div>
|
||||||
|
<div class="overlay">
|
||||||
|
<div class="status">
|
||||||
|
<strong>Device Not Configured</strong>
|
||||||
|
</div>
|
||||||
|
<div class="status">
|
||||||
|
Please scan the configuration RFID card to initialize this device
|
||||||
|
</div>
|
||||||
|
<div class="time" id="time"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function updateTime() {
|
||||||
|
const now = new Date();
|
||||||
|
document.getElementById('time').innerHTML = now.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleImageError() {
|
||||||
|
console.error('Failed to load image');
|
||||||
|
const img = document.querySelector('img');
|
||||||
|
img.alt = 'Image not available';
|
||||||
|
img.style.display = 'none';
|
||||||
|
const wrapper = document.querySelector('.image-wrapper');
|
||||||
|
wrapper.innerHTML = '<div style="color: white; text-align: center;"><h2>Image Loading Failed</h2><p>Please check internet connection</p></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update time immediately and then every second
|
||||||
|
updateTime();
|
||||||
|
setInterval(updateTime, 1000);
|
||||||
|
|
||||||
|
// Prevent screensaver/screen blanking
|
||||||
|
document.addEventListener('mousemove', () => {
|
||||||
|
// Keep screen active
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keypress', () => {
|
||||||
|
// Keep screen active
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
data/html/myimage.jpg
Executable file
BIN
data/html/myimage.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
BIN
data/html/myimage.png
Executable file
BIN
data/html/myimage.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 794 KiB |
@@ -1 +1 @@
|
|||||||
2_15051100_10
|
noconfig
|
||||||
|
|||||||
BIN
data/log.txt
BIN
data/log.txt
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
https://dataswsibiusb01.sibiusb.harting.intra/RO_Quality_PRD/api/record/2_15051100_10/7758885/1/2025-12-19&09:35:25
|
||||||
|
https://dataswsibiusb01.sibiusb.harting.intra/RO_Quality_PRD/api/record/2_15051100_10/7758885/0/2025-12-19&09:35:27
|
||||||
|
|||||||
@@ -652,6 +652,11 @@ def read_name_from_file():
|
|||||||
|
|
||||||
# Function to send logs to a remote server for the Server_monitorizare APP
|
# Function to send logs to a remote server for the Server_monitorizare APP
|
||||||
def send_log_to_server(log_message, n_masa, hostname, device_ip):
|
def send_log_to_server(log_message, n_masa, hostname, device_ip):
|
||||||
|
# Skip sending logs if device is not configured
|
||||||
|
if n_masa == "noconfig":
|
||||||
|
logging.debug(f"Skipping server log (device not configured): {log_message}")
|
||||||
|
return
|
||||||
|
|
||||||
host = hostname
|
host = hostname
|
||||||
device = device_ip
|
device = device_ip
|
||||||
try:
|
try:
|
||||||
@@ -1125,12 +1130,60 @@ def check_internet_connection():
|
|||||||
log_info_with_server(f"An error occurred during internet check: {e}")
|
log_info_with_server(f"An error occurred during internet check: {e}")
|
||||||
time.sleep(60) # Retry after 1 minute in case of an error
|
time.sleep(60) # Retry after 1 minute in case of an error
|
||||||
|
|
||||||
|
# Function to launch Chromium
|
||||||
|
def launch_chromium():
|
||||||
|
"""
|
||||||
|
Launch Chromium with either production URL or local fallback page
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Determine which URL to use based on device configuration
|
||||||
|
if name != "noconfig":
|
||||||
|
# Device is configured - use production URL
|
||||||
|
url = "http://10.76.140.17/iweb_v2/index.php/traceability/production"
|
||||||
|
print(f"Device configured as '{name}'. Launching production URL: {url}")
|
||||||
|
log_info_with_server(f"Launching Chromium with production URL for device: {name}")
|
||||||
|
else:
|
||||||
|
# Device not configured - use local HTML file
|
||||||
|
local_html_dir = "./data/html"
|
||||||
|
local_html_file = os.path.join(local_html_dir, "Screen.html")
|
||||||
|
|
||||||
|
# Create directory if it doesn't exist
|
||||||
|
os.makedirs(local_html_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Check if local HTML file exists
|
||||||
|
if not os.path.exists(local_html_file):
|
||||||
|
print(f"Warning: Local HTML file not found at {local_html_file}")
|
||||||
|
print(f"Please create the file or copy it from the data/html directory")
|
||||||
|
logging.warning(f"Local HTML file not found: {local_html_file}")
|
||||||
|
|
||||||
|
# Convert to file:// URL for local file
|
||||||
|
url = f"file://{os.path.abspath(local_html_file)}"
|
||||||
|
print(f"Device not configured. Launching local fallback page: {url}")
|
||||||
|
log_info_with_server("Device not configured. Launching local fallback page")
|
||||||
|
|
||||||
|
# Launch Chromium with the determined URL - using same parameters as v3
|
||||||
|
print("Starting Chromium...")
|
||||||
|
subprocess.Popen(
|
||||||
|
["chromium", "--test-type", "--noerrors", "--kiosk", "--start-fullscreen",
|
||||||
|
"--unsafely-treat-insecure-origin-as-secure=http://10.76.140.17", url],
|
||||||
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL,
|
||||||
|
start_new_session=True
|
||||||
|
)
|
||||||
|
print("✓ Chromium launched successfully")
|
||||||
|
log_info_with_server("Chromium launched successfully")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Failed to launch Chromium: {e}")
|
||||||
|
log_info_with_server(f"Failed to launch Chromium: {e}")
|
||||||
|
|
||||||
# Start the internet connection check in a separate process
|
# Start the internet connection check in a separate process
|
||||||
internet_check_process = Process(target=check_internet_connection)
|
internet_check_process = Process(target=check_internet_connection)
|
||||||
internet_check_process.start()
|
internet_check_process.start()
|
||||||
url = "10.76.140.17/iweb_v2/index.php/traceability/production" # pentru cazul in care raspberiul nu are sistem de prezenta
|
|
||||||
# Launch Chromium with the specified URLs
|
# Launch Chromium in any situation
|
||||||
subprocess.Popen(["chromium", "--test-type", "--noerrors", "--kiosk", "--start-fullscreen", "--unsafely-treat-insecure-origin-as-secure=http://10.76.140.17", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL, start_new_session=True)
|
print("Initializing Chromium launcher...")
|
||||||
|
time.sleep(2) # Give system time to stabilize
|
||||||
|
launch_chromium()
|
||||||
|
|
||||||
info = "0"
|
info = "0"
|
||||||
#function to post info
|
#function to post info
|
||||||
|
|||||||
Reference in New Issue
Block a user