Add machine status tracking and update for ArchiveSynchronizer
The ArchiveSynchronizer now tracks machine status and sends updates about it. Options of status are tracked as "working", "logged-in", and "logged-out". This implementation includes configuration changes for the st-ten-10 machine and error reporting for failures during remote archive operations.
This commit is contained in:
parent
414d8431c1
commit
85c1ec2d2d
@ -8,3 +8,4 @@ st-ten-6: st-ten-6
|
|||||||
st-ten-7: st-ten-7
|
st-ten-7: st-ten-7
|
||||||
st-ten-8: st-ten-8
|
st-ten-8: st-ten-8
|
||||||
ST-TEN-9: st-ten-9
|
ST-TEN-9: st-ten-9
|
||||||
|
st-ten-10: st-ten-10
|
||||||
|
|||||||
@ -3,7 +3,7 @@ description = ST-TEN-10
|
|||||||
instruction_folder = st-ten-10
|
instruction_folder = st-ten-10
|
||||||
|
|
||||||
[hardware_config]
|
[hardware_config]
|
||||||
archive_synchronizer: absent
|
archive_synchronizer: present
|
||||||
label_printer: present
|
label_printer: present
|
||||||
label_printer_2: present # Brother label printer used only in st-ten-10
|
label_printer_2: present # Brother label printer used only in st-ten-10
|
||||||
remote_api: absent
|
remote_api: absent
|
||||||
@ -16,8 +16,8 @@ leak_disabled: active #disable the tecna_t3 and furness_controls from starting
|
|||||||
|
|
||||||
[archive_synchronizer]
|
[archive_synchronizer]
|
||||||
archive_endpoint: https://satilportal.it/api/st-ten-save/
|
archive_endpoint: https://satilportal.it/api/st-ten-save/
|
||||||
poll_time: 60
|
poll_time: 10
|
||||||
hold_time: 1
|
hold_time: 10
|
||||||
|
|
||||||
#[furness_controls]
|
#[furness_controls]
|
||||||
#port: COM3
|
#port: COM3
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@ -13,19 +16,22 @@ from requests.adapters import HTTPAdapter, Retry
|
|||||||
from urllib3.exceptions import InsecureRequestWarning
|
from urllib3.exceptions import InsecureRequestWarning
|
||||||
|
|
||||||
from .component import Component
|
from .component import Component
|
||||||
|
|
||||||
# Suppress insecure request warning
|
# Suppress insecure request warning
|
||||||
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
||||||
|
|
||||||
|
|
||||||
class ArchiveSynchronizer(Component):
|
class ArchiveSynchronizer(Component):
|
||||||
|
machine_status = "offline"
|
||||||
def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True):
|
def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True):
|
||||||
super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded)
|
super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded)
|
||||||
self.simulate = "--sim-archiver" in sys.argv
|
self.simulate = "--sim-archiver" in sys.argv
|
||||||
|
self.status= ArchiveSynchronizer.machine_status
|
||||||
|
|
||||||
def config_changed(self):
|
def config_changed(self):
|
||||||
self.machine_id = self.config.machine_id
|
self.machine_id = self.config.machine_id
|
||||||
self.archive_endpoint = self.config[self.name]["archive_endpoint"]
|
if "--dev-portal" in sys.argv:
|
||||||
|
self.archive_endpoint =f"https://dev.r5portal.it/api/st-ten-save/"
|
||||||
|
else:
|
||||||
|
self.archive_endpoint = self.config[self.name]["archive_endpoint"]
|
||||||
|
#self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id_endpoint}&status={self.status}"
|
||||||
# self.images_path = self.config[self.name]["images_path"]
|
# self.images_path = self.config[self.name]["images_path"]
|
||||||
self._do_set_period({"period": float(self.config[self.name]["poll_time"])})
|
self._do_set_period({"period": float(self.config[self.name]["poll_time"])})
|
||||||
self.hold_time = round(float(self.config[self.name]["hold_time"]) * 1000)
|
self.hold_time = round(float(self.config[self.name]["hold_time"]) * 1000)
|
||||||
@ -49,9 +55,48 @@ class ArchiveSynchronizer(Component):
|
|||||||
if self.hold_time > 0:
|
if self.hold_time > 0:
|
||||||
QThread.msleep(self.hold_time)
|
QThread.msleep(self.hold_time)
|
||||||
self.gcs_bucket = None
|
self.gcs_bucket = None
|
||||||
|
if "--dev-portal" in sys.argv:
|
||||||
|
self.update_machine_status()
|
||||||
super()._get()
|
super()._get()
|
||||||
|
|
||||||
|
def update_machine_status(self):
|
||||||
|
self.status = ArchiveSynchronizer.machine_status
|
||||||
|
#print(f"machine_status_global: {ArchiveSynchronizer.machine_status}") # TESTING
|
||||||
|
self.status_endpoint = f"https://dev.r5portal.it/api/device-info-update?machine-id={self.machine_id.upper()}&status={self.status}"
|
||||||
|
|
||||||
|
if self.status not in ["working", "logged-in", "logged-out"]:
|
||||||
|
status_dict = {"last_status": "offline"}
|
||||||
|
else:
|
||||||
|
status_dict = {"last_status": self.status}
|
||||||
|
|
||||||
|
response = None
|
||||||
|
try:
|
||||||
|
if not self.simulate:
|
||||||
|
with requests.Session() as s:
|
||||||
|
s.mount("", HTTPAdapter(max_retries=Retry(total=0))) # this disables retries
|
||||||
|
response = requests.post(self.status_endpoint, json=status_dict, timeout=5, verify=False)
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise AssertionError("bad status response")
|
||||||
|
except AssertionError as e:
|
||||||
|
self.log.warning(
|
||||||
|
f"Status: {self.status}: failed to update machine status: {str(e)}: {response.status_code if response else 'no response'}: {response.content if response else 'no response'}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
except (requests.ConnectionError, requests.Timeout) as e:
|
||||||
|
self.log.warning(
|
||||||
|
f"Status: {self.status}: failed to update machine status, archive_endpoint might be unreachable: {str(e)}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
self.log.error(
|
||||||
|
f"Status: {self.status}: failed to update machine status:\n{traceback.format_exc()}:\n{response.status_code if response else 'no response'}: {response.content if response else 'no response'}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.log.info(f"Status: {self.status}: Machine Status Updated Successfully")
|
||||||
|
return True
|
||||||
def remote_archive(self, record):
|
def remote_archive(self, record):
|
||||||
|
r = None
|
||||||
try:
|
try:
|
||||||
if not self.simulate:
|
if not self.simulate:
|
||||||
with requests.Session() as s:
|
with requests.Session() as s:
|
||||||
@ -74,10 +119,6 @@ class ArchiveSynchronizer(Component):
|
|||||||
except (requests.ConnectionError, requests.Timeout) as e:
|
except (requests.ConnectionError, requests.Timeout) as e:
|
||||||
self.log.warning(f"id: {record.id}: failed to archive remotely, archive_endpoint might be unreachable: {str(e)}")
|
self.log.warning(f"id: {record.id}: failed to archive remotely, archive_endpoint might be unreachable: {str(e)}")
|
||||||
return False
|
return False
|
||||||
except Exception:
|
|
||||||
self.log.error(f"id: {record.id}: failed to archive remotely:\n{traceback.format_exc()}:\n{r.status_code}: {r.content}")
|
|
||||||
return False
|
|
||||||
self.log.info(f"id: {record.id}: archived remotely")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def remote_store(self, record):
|
def remote_store(self, record):
|
||||||
|
|||||||
@ -80,7 +80,6 @@ try:
|
|||||||
|
|
||||||
class Main(QObject):
|
class Main(QObject):
|
||||||
do = pyqtSignal(dict)
|
do = pyqtSignal(dict)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _do(config):
|
def _do(config):
|
||||||
return config["f"](*config.get("a", []), **config.get("k", {}))
|
return config["f"](*config.get("a", []), **config.get("k", {}))
|
||||||
@ -250,6 +249,7 @@ try:
|
|||||||
Recipe_Selection, Barcode_Recipe_Selection):
|
Recipe_Selection, Barcode_Recipe_Selection):
|
||||||
# LOGOUT IMMEDIATELY IF NOT TESTING
|
# LOGOUT IMMEDIATELY IF NOT TESTING
|
||||||
Users.logout()
|
Users.logout()
|
||||||
|
ArchiveSynchronizer.machine_status = "logged-out"
|
||||||
self.open_login()
|
self.open_login()
|
||||||
else:
|
else:
|
||||||
if not self.main_window.centralWidget().autotesting:
|
if not self.main_window.centralWidget().autotesting:
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from components import ArchiveSynchronizer
|
||||||
from lib.db import Session, Users
|
from lib.db import Session, Users
|
||||||
from PyQt5.QtCore import QTimer, pyqtSignal
|
from PyQt5.QtCore import QTimer, pyqtSignal
|
||||||
from PyQt5.QtGui import QKeySequence, QIcon
|
from PyQt5.QtGui import QKeySequence, QIcon
|
||||||
@ -21,6 +21,9 @@ class Login(Widget):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.welcome_l.setText("BENVENUTO, PER INIZIARE IL COLLAUDO, EFFETTUA L'ACCESSO:")
|
self.welcome_l.setText("BENVENUTO, PER INIZIARE IL COLLAUDO, EFFETTUA L'ACCESSO:")
|
||||||
self.user_cb.addItems(Users.get_usernames())
|
self.user_cb.addItems(Users.get_usernames())
|
||||||
|
|
||||||
|
ArchiveSynchronizer.machine_status = "logged-in"
|
||||||
|
|
||||||
QShortcut(QKeySequence("Return"), self).activated.connect(self.login_b.click)
|
QShortcut(QKeySequence("Return"), self).activated.connect(self.login_b.click)
|
||||||
QShortcut(QKeySequence("Enter"), self).activated.connect(self.login_b.click)
|
QShortcut(QKeySequence("Enter"), self).activated.connect(self.login_b.click)
|
||||||
self.login_b.clicked.connect(self.try_login)
|
self.login_b.clicked.connect(self.try_login)
|
||||||
@ -56,6 +59,7 @@ class Login(Widget):
|
|||||||
login_count += 1
|
login_count += 1
|
||||||
# /TESTING
|
# /TESTING
|
||||||
self.successful_login.emit()
|
self.successful_login.emit()
|
||||||
|
ArchiveSynchronizer.machine_status = "logged-in"
|
||||||
|
|
||||||
def show_osk(self):
|
def show_osk(self):
|
||||||
self.password_le.setFocus()
|
self.password_le.setFocus()
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import weakref
|
import weakref
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from components import ArchiveSynchronizer
|
||||||
from PyQt5.QtCore import QTimer, pyqtSlot
|
from PyQt5.QtCore import QTimer, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
from lib.db import Archive, Steps, Users
|
from lib.db import Archive, Steps, Users
|
||||||
@ -245,6 +245,10 @@ class Test(Widget):
|
|||||||
self.log.info(f"cycle step: {model_to_dict(self.step)!r} action: {action!r} current index:{self.cycle_index}")
|
self.log.info(f"cycle step: {model_to_dict(self.step)!r} action: {action!r} current index:{self.cycle_index}")
|
||||||
else:
|
else:
|
||||||
self.log.info(f"cycle step: {self.step!r} action: {action!r} current index:{self.cycle_index}")
|
self.log.info(f"cycle step: {self.step!r} action: {action!r} current index:{self.cycle_index}")
|
||||||
|
|
||||||
|
ArchiveSynchronizer.machine_status = "working"
|
||||||
|
# print(f"{ArchiveSynchronizer.machine_status}")#testing
|
||||||
|
|
||||||
current_w = self.centralWidget
|
current_w = self.centralWidget
|
||||||
if hasattr(current_w, "stop"):
|
if hasattr(current_w, "stop"):
|
||||||
current_w.stop()
|
current_w.stop()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user