Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
87e1e18ad3
@ -32,12 +32,12 @@ minimum_disk_free_space_gb: 20
|
|||||||
resize_resolution: 612x512
|
resize_resolution: 612x512
|
||||||
|
|
||||||
[archive_synchronizer]
|
[archive_synchronizer]
|
||||||
archive_endpoint: https://r5portal.it/api/echo/
|
archive_endpoint: https://r5portal.it/api/st-ten-save/
|
||||||
images_path: data/images
|
images_path: data/images
|
||||||
poll_time: 60
|
poll_time: 60
|
||||||
hold_time: 1
|
hold_time: 1
|
||||||
service_account_json: data/secrets/errecinque-prodserver-9d4024fe9eed.json
|
service_account_json: data/secrets/errecinque-prodserver-d132c3d469cc.json
|
||||||
bucket_id: MACHINE
|
bucket_id: st_ten_img
|
||||||
|
|
||||||
[label_printer]
|
[label_printer]
|
||||||
platform: windows
|
platform: windows
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
[hardware_config]
|
[hardware_config]
|
||||||
archive_synchronizer: absent
|
archive_synchronizer: present
|
||||||
galaxy_camera: present
|
galaxy_camera: present
|
||||||
label_printer: present
|
label_printer: present
|
||||||
multicomp: present
|
multicomp: present
|
||||||
@ -18,3 +18,7 @@ port: /dev/ttyACM0
|
|||||||
|
|
||||||
[neo_pixels]
|
[neo_pixels]
|
||||||
port: /dev/ttyACM1
|
port: /dev/ttyACM1
|
||||||
|
|
||||||
|
[archive_synchronizer]
|
||||||
|
poll_time: 6
|
||||||
|
hold_time: 1
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
@ -25,7 +26,7 @@ class ArchiveSynchronizer(Component):
|
|||||||
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"]
|
self.archive_endpoint = self.config[self.name]["archive_endpoint"]
|
||||||
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)
|
||||||
self.gcs_client = storage.Client.from_service_account_json(self.config[self.name]["service_account_json"])
|
self.gcs_client = storage.Client.from_service_account_json(self.config[self.name]["service_account_json"])
|
||||||
@ -55,13 +56,14 @@ class ArchiveSynchronizer(Component):
|
|||||||
with requests.Session() as s:
|
with requests.Session() as s:
|
||||||
s.mount("", HTTPAdapter(max_retries=Retry(total=0))) # this disables retries
|
s.mount("", HTTPAdapter(max_retries=Retry(total=0))) # this disables retries
|
||||||
r = requests.post(self.archive_endpoint, params={
|
r = requests.post(self.archive_endpoint, params={
|
||||||
|
"data": json.dumps(record.test_data),
|
||||||
"machine_id": self.machine_id,
|
"machine_id": self.machine_id,
|
||||||
|
"overridden": record.overridden,
|
||||||
|
"recipe": record.test_data.get("recipe", {}).get("name", None),
|
||||||
|
"result": "OK" if record.result else "KO",
|
||||||
|
"serial": record.id,
|
||||||
"time": record.time.isoformat(),
|
"time": record.time.isoformat(),
|
||||||
"user": record.user.username,
|
"user": record.user.username,
|
||||||
"recipe": record.recipe.name,
|
|
||||||
"test_data": json.dumps(record.test_data),
|
|
||||||
"result": record.result,
|
|
||||||
"overridden": record.overridden,
|
|
||||||
}, timeout=5, verify=False)
|
}, timeout=5, verify=False)
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
raise AssertionError("bad status response")
|
raise AssertionError("bad status response")
|
||||||
@ -78,6 +80,8 @@ class ArchiveSynchronizer(Component):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def remote_store(self, record):
|
def remote_store(self, record):
|
||||||
|
if "vision" not in record.test_data:
|
||||||
|
return True
|
||||||
try:
|
try:
|
||||||
self.gcs_bucket = self.gcs_client.get_bucket(self.bucket_id, timeout=(5, 30), retry=None) # retry=None seems to be ignored
|
self.gcs_bucket = self.gcs_client.get_bucket(self.bucket_id, timeout=(5, 30), retry=None) # retry=None seems to be ignored
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -85,20 +89,21 @@ class ArchiveSynchronizer(Component):
|
|||||||
self.gcs_bucket = None
|
self.gcs_bucket = None
|
||||||
if self.gcs_bucket is None:
|
if self.gcs_bucket is None:
|
||||||
return False
|
return False
|
||||||
dt = record.vision_time
|
for path in record.test_data["vision"]["0"]["files"]:
|
||||||
timestamp = dt.strftime(self.time_format)
|
dt = record.time
|
||||||
img_in = f"{self.images_path}/frames/{dt.strftime('%Y')}/{dt.strftime('%m')}/{timestamp}.png"
|
# path_in = f"{self.images_path}/{dt.strftime('%Y')}/{dt.strftime('%m')}/{os.path.basename(path)}"
|
||||||
img_out = f"{self.bench.type}/{dt.strftime('%Y')}/{dt.strftime('%m')}/{timestamp}.png"
|
path_in = path
|
||||||
|
path_out = f"{self.machine_id}/{dt.strftime('%Y')}/{dt.strftime('%m')}/{os.path.basename(path)}"
|
||||||
try:
|
try:
|
||||||
blob = self.gcs_bucket.blob(img_out)
|
blob = self.gcs_bucket.blob(path_out)
|
||||||
if not self.simulate:
|
if not self.simulate:
|
||||||
blob.upload_from_filename(filename=img_in)
|
blob.upload_from_filename(filename=path_in)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.log.error(f"id {record.id}: {img_in}: file not found.")
|
self.log.error(f"id {record.id}: {path_in}: file not found.")
|
||||||
return False
|
return False
|
||||||
except Forbidden as e:
|
except Forbidden as e:
|
||||||
if re.match("^Object '.*?' is subject to bucket's retention policy and cannot be deleted, overwritten or archived until .*?$", e._response.json()["error"]["message"]) is not None:
|
if re.match("^Object '.*?' is subject to bucket's retention policy and cannot be deleted, overwritten or archived until .*?$", e._response.json()["error"]["message"]) is not None:
|
||||||
self.log.info(f"id {record.id}: {img_in}: already stored.")
|
self.log.info(f"id {record.id}: {path_in}: already stored.")
|
||||||
else:
|
else:
|
||||||
self.log.warning(f"id: {record.id}: failed to store remotely: {str(e)}: {e._response.json()}")
|
self.log.warning(f"id: {record.id}: failed to store remotely: {str(e)}: {e._response.json()}")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@ -81,7 +81,7 @@ class VisionSaver(Component):
|
|||||||
# save vision
|
# save vision
|
||||||
with open(out_paths[-1], "w") as f:
|
with open(out_paths[-1], "w") as f:
|
||||||
json.dump(vision, f)
|
json.dump(vision, f)
|
||||||
return out_paths
|
return list(map(str, out_paths))
|
||||||
|
|
||||||
def remove_older_images_if_needed(self):
|
def remove_older_images_if_needed(self):
|
||||||
if self.minimum_disk_free_space_gb is None:
|
if self.minimum_disk_free_space_gb is None:
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class Archive(Widget):
|
|||||||
# "id": "Id",
|
# "id": "Id",
|
||||||
# "time": "Data e ora",
|
# "time": "Data e ora",
|
||||||
# "user": "Operatore",
|
# "user": "Operatore",
|
||||||
# "recipe": "Ricetta",
|
# "test_data.recipe.name": "Ricetta",
|
||||||
# "result": "Esito",
|
# "result": "Esito",
|
||||||
# "overridden": "Esito forzato",
|
# "overridden": "Esito forzato",
|
||||||
# "test_data": "Dati del test",
|
# "test_data": "Dati del test",
|
||||||
@ -27,7 +27,7 @@ class Archive(Widget):
|
|||||||
crud_aliases = {
|
crud_aliases = {
|
||||||
"time": "Data e ora",
|
"time": "Data e ora",
|
||||||
"user": "Operatore",
|
"user": "Operatore",
|
||||||
"recipe": "Ricetta",
|
"test_data.recipe.name": "Ricetta",
|
||||||
"result": "Esito",
|
"result": "Esito",
|
||||||
"overridden": "Esito forzato",
|
"overridden": "Esito forzato",
|
||||||
"test_data": "Dati del test",
|
"test_data": "Dati del test",
|
||||||
|
|||||||
@ -363,7 +363,7 @@ class Crud(Widget):
|
|||||||
if text != self.filters.get(fn, None):
|
if text != self.filters.get(fn, None):
|
||||||
self.filters[fn] = text
|
self.filters[fn] = text
|
||||||
self.db.filter(self.select[cn], text)
|
self.db.filter(self.select[cn], text)
|
||||||
self.refresh()
|
self.refresh(filter_cn=cn)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_row_upgrader(row, row_number, crud):
|
def default_row_upgrader(row, row_number, crud):
|
||||||
@ -393,7 +393,7 @@ class Crud(Widget):
|
|||||||
fails.append(str(e))
|
fails.append(str(e))
|
||||||
return r, fail, fails
|
return r, fail, fails
|
||||||
|
|
||||||
def refresh(self, action=None, page=0):
|
def refresh(self, action=None, page=0, filter_cn=None):
|
||||||
# IGNORE SIGNALS WHILE UPDATING
|
# IGNORE SIGNALS WHILE UPDATING
|
||||||
self.db_tw.blockSignals(True)
|
self.db_tw.blockSignals(True)
|
||||||
self._modified = False # force reset modified status
|
self._modified = False # force reset modified status
|
||||||
@ -472,6 +472,10 @@ class Crud(Widget):
|
|||||||
w.setPlaceholderText("Non filtrabile")
|
w.setPlaceholderText("Non filtrabile")
|
||||||
w.setEnabled(False)
|
w.setEnabled(False)
|
||||||
self.db_tw.setCellWidget(0, cn, w)
|
self.db_tw.setCellWidget(0, cn, w)
|
||||||
|
if filter_cn is not None:
|
||||||
|
w = self.db_tw.cellWidget(0, filter_cn)
|
||||||
|
if w is not None:
|
||||||
|
w.setFocus()
|
||||||
# INSERT UPDATED DATA
|
# INSERT UPDATED DATA
|
||||||
for rn, r in enumerate(data, start=1): # start=1 because rn starts from 1 (filters line)
|
for rn, r in enumerate(data, start=1): # start=1 because rn starts from 1 (filters line)
|
||||||
r = self.row_upgrader(r, rn, self)
|
r = self.row_upgrader(r, rn, self)
|
||||||
|
|||||||
@ -309,7 +309,7 @@ class Test(Widget):
|
|||||||
self.data[step_name] = {}
|
self.data[step_name] = {}
|
||||||
if data is not None:
|
if data is not None:
|
||||||
data["step"] = model_to_dict(self.step)
|
data["step"] = model_to_dict(self.step)
|
||||||
self.data[step_name][len(self.data[step_name])] = data
|
self.data[step_name][str(len(self.data[step_name]))] = data
|
||||||
self.data["overridden"] = self.data["overridden"] or data.get("overridden", False)
|
self.data["overridden"] = self.data["overridden"] or data.get("overridden", False)
|
||||||
self.data["ok"] = self.data["ok"] and data.get("ok", False)
|
self.data["ok"] = self.data["ok"] and data.get("ok", False)
|
||||||
self.next()
|
self.next()
|
||||||
@ -317,12 +317,13 @@ class Test(Widget):
|
|||||||
def done(self, ok=True):
|
def done(self, ok=True):
|
||||||
self.log.info("cycle done")
|
self.log.info("cycle done")
|
||||||
if "vision" in self.data:
|
if "vision" in self.data:
|
||||||
vision_test_1 = self.data.get("vision", {}).get(0, {})
|
vision_test_1 = self.data.get("vision", {}).get("0", {})
|
||||||
out_paths = self.components["vision_saver"].save(
|
out_paths = self.components["vision_saver"].save(
|
||||||
save_time=vision_test_1.get("time", None),
|
save_time=vision_test_1.get("time", None),
|
||||||
frame=vision_test_1.get("frame", None),
|
frame=vision_test_1.get("frame", None),
|
||||||
# vision=vision_test_1.get("detections", None),
|
# vision=vision_test_1.get("detections", None),
|
||||||
)
|
)
|
||||||
|
self.data.get("vision", {}).get("0", {})["files"] = out_paths
|
||||||
self.log.info(f"cycle vision saved locally: {out_paths!r}")
|
self.log.info(f"cycle vision saved locally: {out_paths!r}")
|
||||||
for vision in self.data.get("vision", {}).values():
|
for vision in self.data.get("vision", {}).values():
|
||||||
vision.pop("frame", None)
|
vision.pop("frame", None)
|
||||||
@ -347,7 +348,7 @@ class Test(Widget):
|
|||||||
self.log.info("cycle printed already compiled label")
|
self.log.info("cycle printed already compiled label")
|
||||||
# LABEL PRINT
|
# LABEL PRINT
|
||||||
recipe = archived.test_data.get("recipe", {})
|
recipe = archived.test_data.get("recipe", {})
|
||||||
leak_test_1 = archived.test_data.get("leak", {}).get(0, {})
|
leak_test_1 = archived.test_data.get("leak", {}).get("0", {})
|
||||||
leak_test_1_step = leak_test_1.get("step", {})
|
leak_test_1_step = leak_test_1.get("step", {})
|
||||||
leak_test_1_step_spec = leak_test_1_step.get("spec", {})
|
leak_test_1_step_spec = leak_test_1_step.get("spec", {})
|
||||||
leak_test_1_results = leak_test_1.get("results", {})
|
leak_test_1_results = leak_test_1.get("results", {})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user