imager add uuid for each acquisition and check for id reuse
This commit is contained in:
parent
8e70723310
commit
13307476e2
|
@ -33,6 +33,9 @@ import planktoscope.raspimjpeg
|
||||||
# Integrity verification module
|
# Integrity verification module
|
||||||
import planktoscope.integrity
|
import planktoscope.integrity
|
||||||
|
|
||||||
|
# Uuid module
|
||||||
|
import planktoscope.uuidName
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Streaming PiCamera over server
|
# Streaming PiCamera over server
|
||||||
|
@ -294,6 +297,7 @@ class ImagerProcess(multiprocessing.Process):
|
||||||
"sleep" not in last_message
|
"sleep" not in last_message
|
||||||
or "volume" not in last_message
|
or "volume" not in last_message
|
||||||
or "nb_frame" not in last_message
|
or "nb_frame" not in last_message
|
||||||
|
or "pump_direction" not in last_message
|
||||||
):
|
):
|
||||||
logger.error(f"The received message has the wrong argument {last_message}")
|
logger.error(f"The received message has the wrong argument {last_message}")
|
||||||
self.imager_client.client.publish("status/imager", '{"status":"Error"}')
|
self.imager_client.client.publish("status/imager", '{"status":"Error"}')
|
||||||
|
@ -303,6 +307,7 @@ class ImagerProcess(multiprocessing.Process):
|
||||||
|
|
||||||
# Get duration to wait before an image from the different received arguments
|
# Get duration to wait before an image from the different received arguments
|
||||||
self.__sleep_before = float(last_message["sleep"])
|
self.__sleep_before = float(last_message["sleep"])
|
||||||
|
|
||||||
# Get volume in between two images from the different received arguments
|
# Get volume in between two images from the different received arguments
|
||||||
self.__pump_volume = float(last_message["volume"])
|
self.__pump_volume = float(last_message["volume"])
|
||||||
|
|
||||||
|
@ -312,6 +317,9 @@ class ImagerProcess(multiprocessing.Process):
|
||||||
# Get the number of frames to image from the different received arguments
|
# Get the number of frames to image from the different received arguments
|
||||||
self.__img_goal = int(last_message["nb_frame"])
|
self.__img_goal = int(last_message["nb_frame"])
|
||||||
|
|
||||||
|
# Reset the counter to 0
|
||||||
|
self.__img_done = 0
|
||||||
|
|
||||||
self.imager_client.client.publish("status/imager", '{"status":"Started"}')
|
self.imager_client.client.publish("status/imager", '{"status":"Started"}')
|
||||||
|
|
||||||
def __message_stop(self, last_message):
|
def __message_stop(self, last_message):
|
||||||
|
@ -342,21 +350,10 @@ class ImagerProcess(multiprocessing.Process):
|
||||||
"status/imager", '{"status":"Configuration message error"}'
|
"status/imager", '{"status":"Configuration message error"}'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info("Updating the configuration now with the received data")
|
logger.info("Updating the configuration now with the received data")
|
||||||
# Updating the configuration with the passed parameter in payload["config"]
|
# Updating the configuration with the passed parameter in payload["config"]
|
||||||
nodered_metadata = last_message["config"]
|
self.__global_metadata = last_message["config"]
|
||||||
# Definition of the few important metadata
|
|
||||||
local_metadata = {
|
|
||||||
"process_datetime": datetime.datetime.now().isoformat().split(".")[0],
|
|
||||||
"acq_camera_resolution": self.__resolution,
|
|
||||||
"acq_camera_iso": self.__iso,
|
|
||||||
"acq_camera_shutter_speed": self.__shutter_speed,
|
|
||||||
}
|
|
||||||
# TODO add here the field size metadata
|
|
||||||
# For cam HQ 4,15mm x 3,14mm, résolution 1µm/px
|
|
||||||
# For cam 2.1 2.31mm x 1,74mm, résolution 0.7µm/px
|
|
||||||
# Concat the local metadata and the metadata from Node-RED
|
|
||||||
self.__global_metadata = {**local_metadata, **nodered_metadata}
|
|
||||||
|
|
||||||
# Publish the status "Config updated" to via MQTT to Node-RED
|
# Publish the status "Config updated" to via MQTT to Node-RED
|
||||||
self.imager_client.client.publish(
|
self.imager_client.client.publish(
|
||||||
|
@ -558,32 +555,58 @@ class ImagerProcess(multiprocessing.Process):
|
||||||
)
|
)
|
||||||
|
|
||||||
def __state_imaging(self):
|
def __state_imaging(self):
|
||||||
# TODO we should make sure here that we are not writing to an existing folder
|
|
||||||
# otherwise we might overwrite the metadata.json file
|
|
||||||
|
|
||||||
# subscribe to status/pump
|
# subscribe to status/pump
|
||||||
self.imager_client.client.subscribe("status/pump")
|
self.imager_client.client.subscribe("status/pump")
|
||||||
self.imager_client.client.message_callback_add(
|
self.imager_client.client.message_callback_add(
|
||||||
"status/pump", self.pump_callback
|
"status/pump", self.pump_callback
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Definition of the few important metadata
|
||||||
|
local_metadata = {
|
||||||
|
"acq_local_datetime": datetime.datetime.now().isoformat().split(".")[0],
|
||||||
|
"acq_camera_resolution": self.__resolution,
|
||||||
|
"acq_camera_iso": self.__iso,
|
||||||
|
"acq_camera_shutter_speed": self.__shutter_speed,
|
||||||
|
"acq_uuid": planktoscope.uuidName.uuidMachineName(
|
||||||
|
machine=planktoscope.uuidName.getSerial()
|
||||||
|
),
|
||||||
|
"sample_uuid": planktoscope.uuidName.uuidMachineName(
|
||||||
|
machine=planktoscope.uuidName.getSerial()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Concat the local metadata and the metadata from Node-RED
|
||||||
|
self.__global_metadata = {**self.__global_metadata, **local_metadata}
|
||||||
|
|
||||||
logger.info("Setting up the directory structure for storing the pictures")
|
logger.info("Setting up the directory structure for storing the pictures")
|
||||||
self.__export_path = os.path.join(
|
self.__export_path = os.path.join(
|
||||||
self.__base_path,
|
self.__base_path,
|
||||||
# We only keep the date '2020-09-25T15:25:21.079769'
|
self.__global_metadata["object_date"],
|
||||||
self.__global_metadata["process_datetime"].split("T")[0],
|
|
||||||
str(self.__global_metadata["sample_id"]),
|
str(self.__global_metadata["sample_id"]),
|
||||||
str(self.__global_metadata["acq_id"]),
|
str(self.__global_metadata["acq_id"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not os.path.exists(self.__export_path):
|
if os.path.exists(self.__export_path):
|
||||||
|
# If this path exists, then ids are reused when they should not
|
||||||
|
logger.error(f"The export path at {self.__export_path} already exists")
|
||||||
|
self.imager_client.client.publish(
|
||||||
|
"status/imager",
|
||||||
|
'{"status":"Configuration update error: Chosen id are already in use!"}',
|
||||||
|
)
|
||||||
|
# Reset the counter to 0
|
||||||
|
self.__img_done = 0
|
||||||
|
# Change state towards stop
|
||||||
|
self.__imager.change(planktoscope.imager_state_machine.Stop)
|
||||||
|
planktoscope.light.error()
|
||||||
|
return
|
||||||
|
else:
|
||||||
# create the path!
|
# create the path!
|
||||||
os.makedirs(self.__export_path)
|
os.makedirs(self.__export_path)
|
||||||
|
|
||||||
# Export the metadata to a json file
|
# Export the metadata to a json file
|
||||||
logger.info("Exporting the metadata to a metadata.json")
|
logger.info("Exporting the metadata to a metadata.json")
|
||||||
config_path = os.path.join(self.__export_path, "metadata.json")
|
metadata_filepath = os.path.join(self.__export_path, "metadata.json")
|
||||||
with open(config_path, "w") as metadata_file:
|
with open(metadata_filepath, "w") as metadata_file:
|
||||||
json.dump(self.__global_metadata, metadata_file)
|
json.dump(self.__global_metadata, metadata_file)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Metadata dumped in {metadata_file} are {self.__global_metadata}"
|
f"Metadata dumped in {metadata_file} are {self.__global_metadata}"
|
||||||
|
@ -596,11 +619,16 @@ class ImagerProcess(multiprocessing.Process):
|
||||||
logger.info(
|
logger.info(
|
||||||
f"The integrity file already exists in this export path {self.__export_path}"
|
f"The integrity file already exists in this export path {self.__export_path}"
|
||||||
)
|
)
|
||||||
|
# Add the metadata.json file to the integrity file
|
||||||
|
try:
|
||||||
|
planktoscope.integrity.append_to_integrity_file(metadata_filepath)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
logger.error(
|
||||||
|
f"{metadata_filepath} was not found, the metadata.json may not have been created properly!"
|
||||||
|
)
|
||||||
|
|
||||||
self.__pump_message()
|
self.__pump_message()
|
||||||
|
|
||||||
# FIXME We should probably update the global metadata here with the current datetime/position/etc...
|
|
||||||
|
|
||||||
# Change state towards Waiting for pump
|
# Change state towards Waiting for pump
|
||||||
self.__imager.change(planktoscope.imager_state_machine.Waiting)
|
self.__imager.change(planktoscope.imager_state_machine.Waiting)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ def popHexPair(s):
|
||||||
|
|
||||||
def uuidMachineName(machine="", type=1):
|
def uuidMachineName(machine="", type=1):
|
||||||
"""Generates a universally unique name, including the machine name
|
"""Generates a universally unique name, including the machine name
|
||||||
|
|
||||||
When using a type 4 id, the machine name is not taken into account as the uuid is completely random
|
When using a type 4 id, the machine name is not taken into account as the uuid is completely random
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -38,7 +39,7 @@ def uuidMachineName(machine="", type=1):
|
||||||
if machine == "":
|
if machine == "":
|
||||||
id = str(uuid.uuid1())
|
id = str(uuid.uuid1())
|
||||||
else:
|
else:
|
||||||
id = str(uuid.uuid1(int(str(machine)[-12:], 16)))
|
id = str(uuid.uuid1(node=int(str(machine)[-12:], 16)))
|
||||||
name = ""
|
name = ""
|
||||||
x = id.rsplit("-", 1)
|
x = id.rsplit("-", 1)
|
||||||
machine = x[1]
|
machine = x[1]
|
||||||
|
|
Loading…
Reference in a new issue