def stopkill(self): """Called to stop all scheduled RepeatedFunctions""" try: self.stop_event.set() #no more scheduling new events while len(self.running_rep_functions[:]) != 0: for repfunc_thread in self.running_rep_functions[:]: repfunc_thread.stop_event.set( ) #stop this RepeatedFunction for repfunc_thread in self.running_rep_functions[:]: if not repfunc_thread.is_alive(): self.running_rep_functions.remove(repfunc_thread) logger.debug("removed {}".format(repfunc_thread)) # now self.running_rep_functions is empty self.stop_event.clear() except Exception as e: logger.error("Unexpected Error, sending to cloud {}".format(e)) formatted_publish_message( topic=TOPIC_STATE, payload= "Error scheduling old timing events, consider restarting device: {} " .format(e), c_queue=pub_queue)
def read_setup(pub_queue, sleeptime=True, send_answer_to_cloud=False): port_config = dict() slave_config = dict() checkresult = False time.sleep(random.randint(5, 15) / 10) read_complete = 0 logger.debug("check the setup_modbus.json") while not read_complete >= 5: try: checkresult, response, data_json = modbus_json_check( file=su.setup_modbus_filepath) if send_answer_to_cloud: logger.debug("setup_modbus.json response:" + str(response)) port_config = data_json["port_config"] slave_config = data_json["slaveconfig"] read_complete = 5 if send_answer_to_cloud: gmc.formatted_publish_message( topic=gmc.TOPIC_STATE, payload= "Start up with modbus config: {} JSON CHECKUP {}". format(data_json, response), c_queue=pub_queue) except Exception as e: try: if read_complete > 1: gmc.formatted_publish_message( topic=gmc.TOPIC_STATE, payload="ERROR reading setup_modbus:" + str(e), c_queue=pub_queue) finally: time.sleep( 3 + random.randint(0, 10) ) #randomized access if multiple read at the same time read_complete = read_complete + 1 if not checkresult: #unsuccessful, default port_config = { "port": "COM6", "baudrate": 9600, "databits": 8, "parity": "N", "stopbits": 1, "timeout_connection": 10 } slave_config = {} return port_config, slave_config
def read_modbus_event(self): """read operations of the timing_queue with the Modbus RTU Master and Execute them with """ logger.debug("calling read_modbus_event") while self.serial_connected and self.alive and self.master_status < self.max_master_attemps - 1: request = self.timing_queue.get( ) #blocking call until new request is received if self.alive == False: #discontinue if function is wished to be stopped self.timing_queue.task_done() break slave_id = request["slave_id"] startadress = request["startadress"] function_code = request["function_code"] display_name = request["display_name"] result = (99999, "modbus_request_not_possible") #default try: if "quantity_of_x" in request: result = self.master.execute( slave=slave_id, function_code=function_code, starting_address=startadress, quantity_of_x=request["quantity_of_x"]) #read elif "output_value" in request: result = self.master.execute( slave=slave_id, function_code=function_code, starting_address=startadress, output_value=request["output_value"]) #write logger.debug( "slave no {}, starting_adress {} with name {} and {} ". format(slave_id, startadress, display_name, str(result))) self.master_status = 0 #successfull read, reset to 0 except ModbusError as exc: self.master_status = self.master_status + 1 #unsuccessfull, increase the status logger.warning( "ModbusError in read_modbus_event {}".format(ex)) except Exception as ex: #other error, like serial port etc. logger.warning( "Unexpected error in read_modbus_event {}".format(ex)) self.master_status = self.master_status + 5 #unsuccessfull, increase the status self.serial_connected = False payload = { "na": display_name, "res": result, "sl": slave_id, "time": time.time() } formatted_publish_message(topic=TOPIC_EVENT, payload=payload, c_queue=self.publishing_queue) self.timing_queue.task_done() logger.warning("Disconnected the Modbus, restarting") try: if self.serial_port != "undefined": #if not just initialisized self.serial_port.close() except Exception as ex: logger.error("error closing serial port: {}".format(ex))
def startup(self): """Start or Restart the Scheduling events""" #Step 1: Figure out what current setup_modbus.json is and its slaveconfig unused_port_config, slaveconfig = read_setup( self.publishing_queue) #wait to get newest setup try: while not self.stop_event.is_set(): #Step 2: For every operation in slaveconfig: find out details for slave_name in slaveconfig: #looping through all exisiting slaves operations = slaveconfig[slave_name]["operations"] slave_id = slaveconfig[slave_name]["slave_id"] for operation in operations: #looping for all operations of a specific slave #[Start get Information of Operation] op = operations[operation] interval = (op["sampling_interval"] ) #interval for Scheduling events process_request = { "slave_id": slave_id, "startadress": op["startadress"], "function_code": op["function_code"], "display_name": op["display_name"], } if "quantity_of_x" in op: process_request["quantity_of_x"] = op[ "quantity_of_x"] elif "output_value" in op: process_request["output_value"] = op[ "output_value"] else: logger.error( "FATAL ERROR, no output value or quantity_of_x {}" .format(process_request)) #[End get Information of Operation] self.stop_event.wait( self.timeout_between_functions ) #timeout, so differet request will be executed at different times if self.stop_event.is_set(): logger.warning( "Error: unwanted break in scheduling new RepeatedFunctions" ) return #Step 3: For a specific operation schedule a specific RepeatedFunction every interval seconds #[Start Schedule new RepeatedFunction] rf = RepeatedFunction(interval, self.query_task, (self, process_request)) rf.setDaemon = True rf.start() self.running_rep_functions.append(rf) logger.debug( "scheduleded {} \t at interval {} ".format( process_request, (str(interval) + "s") if interval != 0 else "once occuring")) #[End Schedule new RepeatedFunction] logger.debug("ending this scheduler thread {}".format( self.running_rep_functions)) return except Exception as e: #should in no case occur logger.error( "Error scheduling new timing events, consider restarting device: {}" .format(e)) formatted_publish_message( topic=TOPIC_STATE, payload= "Error scheduling new timing events, consider restarting device: {} " .format(e), c_queue=pub_queue)
def check_configuration_message(config_payload, scheduler_obj, modbus_reader_obj, publising_queue): logger.info("check new message on content") """checks for the Configuration Messages and applies them when the new and deployment formally correct""" answer_config_update = " /Config Subscription Message received" novel_json_content = False # absolute_success_update = False #whether successfull update replacing_file_success = False # content_correct = False # received_json_checkresult = False # current_checkresult, current_response, current_json = modbus_json_check( file=su.setup_modbus_filepath) #answer_config_update = answer_config_update + str(" \n CURRENT JSON running is ") + str(current_json) #current json content_correct = bool("content_start" in config_payload and "content_end" in config_payload and "configuration_update_modbus" in config_payload) if content_correct: #elements of a correct config message exists try: received_json_string = config_payload.split( "content_start")[1].split("content_end")[0] received_json = json.loads( received_json_string ) #will not work, if a invalid json it throws an error received_json_checkresult, received_json_response, unused_json = modbus_json_check( dictio=received_json) if received_json_checkresult == True: answer_config_update = answer_config_update + str( "\n Received JSON is valid") #json is currently used if current_json != received_json: novel_json_content = True logger.debug( "SUCCESS! Received a new, valid JSON. Will update an use: {}" .format(received_json)) result = "UPDATING" # [Start UPDATE] replacing_file_success, answer_update = execute_configuration_message( received_json) #use the new json answer_config_update = answer_config_update + answer_update # [End UPDATE] elif current_json == received_json: answer_config_update = answer_config_update + str( "\n CURRENT JSON is the SAME as received JSON, not changing setup " ) #json is currently used elif received_json_checkresult == False: answer_config_update = answer_config_update + "\n received JSON is invalid: {} ".format( received_json_response) except Exception as e: received_json_checkresult = False answer_config_update = answer_config_update + "\n ERROR content between content_start and content_end is not a JSON {} ".format( e) elif not content_correct: answer_config_update = answer_config_update + str( "\n configuration_update_modbus, content_start, content_end is missing as header, not valid configuration" ) if replacing_file_success: try: logger.debug("config about to be implemented ") scheduler_obj.stopkill() modbus_reader_obj.stopkill() logger.debug("stopped all, wait before starting up") time.sleep(3) logger.debug("starting modbus and scheduler back up") scheduler_obj.startup() modbus_reader_obj.startup() absolute_success_update = True except Exception as e: absolute_success_update = False result = result + "BUT FAILED" logger.debug("config implemented ") if not content_correct: result = " configuration_update_modbus, content_start, content_end is missing as header - NO Further Processing " elif not received_json_checkresult: result = "JSON between content_start and content_end is invalid - NO Further Processing " elif not novel_json_content: result = "JSON sent already in use" else: # JSON was further Processed " if replacing_file_success: if absolute_success_update: result = "SUCCESS, using received_json {} ".format( received_json) elif not absolute_success_update: result = "ERROR JSON was further processed and saved, but not implemented due to an error" if not replacing_file_success: result = "Fatal ERROR JSON was further processed, but writing failed" answer_config_update = answer_config_update + "\n RESULT: {} \n".format( result) logger.info(answer_config_update) gmc.formatted_publish_message(topic=gmc.TOPIC_STATE, payload=answer_config_update, c_queue=publising_queue) return