imager add uuid for each acquisition and check for id reuse

This commit is contained in:
Romain Bazile 2020-12-02 19:25:59 +01:00
parent 8e70723310
commit 13307476e2
2 changed files with 53 additions and 24 deletions

View file

@ -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)

View file

@ -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]