예제 #1
0
	def trigger(self):
		if self.triggerCheck():
			self.triggered = True
			errors.debug(self.getID()+" triggered.")
			return False
		else:
			return True
예제 #2
0
	def trigger(self,triggerer,objects):
		if self.triggerCheck():
			for Object in objects:
				if Object.getID()==self.target:
					Object.setState(self.newState)
					errors.debug(self.getID()+" triggered.")
					self.triggered = True
예제 #3
0
    def build_file_for_dash(self):
        index = 1  #WRITE DATA FOR	DASHBOARD:
        errors.debug("Building converted data file for dash.")
        try:  #this file will be read using pysftp by the dashboard application whenever it loads
            with open("data_for_dash",
                      'a') as fordash:  #open format file and data file
                with open("dashformat.txt", 'r') as dashformat:
                    for line in dashformat:  #for each line in format file
                        if line[:
                                4] == "STR:":  #if the line is a string tag, copy it over
                            fordash.write("CVT\t" + line[4:].strip() + '\n')
                        else:  #if it's a label, copy it over with data appended
                            fordash.write(line.strip() + '\t' +
                                          self.data_list[index] + '\n')
                            index += 1
        except IndexError:
            if not self.for_dash_error:
                errors.error(
                    "Error in parsing dashformat.txt; file may have been " +
                    "corrupted. Dashboard may not display data properly or correctly."
                    + " Error message: " +
                    traceback.format_exc(Config.TRACEBACK_LIMIT))
            else:
                errors.debug(
                    "Error in writing data_for_dash again, don't trust dashboard."
                )
            self.for_dash_error = True

        self.data_list = []
예제 #4
0
	def maybe_end(self):																	#checks if end signal has been received, and ends program if it has
		if self.endToggle:																	#this toggle is set by the signal handler below
			errors.info("Received end signal, terminating main.py. " +						#if ending, send email
						"Use startup.sh to restart.")										
			errors.sendEmail(subject="TS-4200 Stopping Operations")
			errors.debug("main.py exiting.")
			raise SystemExit 																#exit python
		os.system("sudo ts4200ctl --redledon")												#turn on LED
		self.note_running()																	#leave a timestamp for dash
예제 #5
0
	def trigger(self,triggerer,objects):
		if self.triggerCheck():
			for Object in objects:
				if Object.getID()==self.target:
					if Object.getState()==self.primaryState:
						Object.setState(self.secondaryState)
					else:
						Object.setState(self.primaryState)
					errors.debug(self.getID()+" triggered.")
					self.triggered = True
예제 #6
0
	def daily_checks(self):
		"""
		Checks that various parts of the system are healthy: the PIC 
		is not missing strings repeatedly, the board has enough space
		and memory to run properly. Also resets all error flags. Runs
		only every 4320 cycles (24 hours @ 20s/cycle).
		"""
		self.build_file_for_dash()															#put together data for GUI
		errors.debug("daily_checks called.")
		os.system("sudo ts4200ctl --redledoff")												#turn off LED
		self.cycles +=1
		if self.cycles != 1:																#i.e., run only every 24 hours' worth of cycles
			errors.debug("daily_checks exiting without checking.")
			return

		errors.debug("Performing daily checks.")
		self.cycles = 0																		#reset counter
																							#the following 2 checks use the statvfs utility. see statvfs man pages.
																						#check space remaining on local filesystem:
		localStats = os.statvfs(Config.TO_UNIX_FILE_PATH)									#get statvfs data about local filesystem
		freeBytes = localStats.f_frsize * localStats.f_bavail								#free bytes = fragment size * number of fragments available to us
		if freeBytes < Config.FREE_BYTES_WARNING:											#check that this number is acceptable. if not, send an alert.
			errors.error("TS-4200 has " + str(freeBytes/1000000) + " MB remaining. " +
				"This is a serious and unforeseen error. Immediate corrective action " +
				"recommended to determine what is filling up the local filesystem.")

																						#check space remaining on flash drive
		if os.path.ismount(Config.FLASH_BACKUP_DIREC_PATH):									#only try if flash drive is mounted
			usbStats = os.statvfs(Config.FLASH_BACKUP_DIREC_PATH)							#same as previous, except passing statvfs the USB mount point
			freeBytes = usbStats.f_frsize * usbStats.f_bavail
			if freeBytes < Config.FREE_BYTES_WARNING:
				errors.error("Flash drive has " + str(freeBytes/1000000) + " MB remaining. " +
					"Freya will fill this at a rate of about 15MB/week. Replace flash drive.")
 
																						#check RAM usage
		with open("/proc/meminfo", 'r') as meminfo:											#open /proc/meminfo, a special file holding info about RAM usage
			meminfo.readline()																#extract statistics from successive lines of /proc/meminfo
			freemem = int(meminfo.readline().split()[1])									#unused memory is best estimated as "free memory" plus buffered and
			buffermem = int(meminfo.readline().split()[1])									#cached memory, since these are available to be overwritten if a
			cachemem = int(meminfo.readline().split()[1])									#process requires them.
			unusedmem = freemem + buffermem + cachemem
		if unusedmem < Config.UNUSED_MEMORY_WARNING:										#send warning if memory usage is too high
			errors.error("TS-4200 has only " + str(unusedmem) + " kB of " +
				"unused RAM. Speed and performance may be impacted, corrective action recommended.")

		PIC_bad_strings = self.reader.numBadStrings(reset=True)								#get number of bad strings and reset all flags in reader
		if PIC_bad_strings >= Config.TOTAL_BAD_STRING_WARNING:								#send an error if there are too many bad strings
			errors.info("TS-4200 has logged " + str(PIC_bad_strings) + " bad strings " + 
				"(unrecognized ID, wrong length, or unreceived) in last 24 hours. Probable " +
				"mismatch between PIC format and expected format. Be sure that picdata.conf " +
				"is updated to fit what the PIC is sending. Warnings should have been sent " +
				"when problems first happened -- check these for more information on what " +
				"might be going wrong.")
		else:
			errors.debug("Only " + str(PIC_bad_strings) + " bad strings for the day. No warning sent.")

		convert.reset_all_flags()															#resets all data converter error flags
		self.outputter.reset()																#resets outputter's error flags
		self.sched_warning_sent = False 													#reset schedule error flag
		open("text_for_dash", 'w').close()													#stop text_for_dash from ballooning
예제 #7
0
    def __init__(self):
        """Parses outdata.conf into a list, makes a document holding
		format of data to dashboard, and initializes error flags."""
        self.format = []  #this list holds labels of outgoing data in order
        try:
            open("dashformat.txt", 'w').close()  #clear dashformat.txt
            with open("dashformat.txt",
                      'a') as dashformat:  #open dashformat.txt
                with open("outdata.conf", 'r') as outdata:  #open outdata.conf
                    for line in outdata:  #iterate through each line
                        if line == '\n' or line[
                                0] == "#":  #ignore empty lines or lines that start with '#'
                            pass
                        elif line[:4] == "STR:":
                            dashformat.write(line)
                        else:  #append what's left to self.format and dashformat.txt
                            self.format.append(line.strip('\n'))
                            dashformat.write(line)
                            #in the case of errors, send a message and then exit the program:
        except IOError:  #error in finding or reading file (if thrown, most likely outdata.conf does not exist)
            errors.error(
                "FATAL: DataOutputter unable to read outdata.conf. " +
                "TS-4200 will not be able to output data until fixed. " +
                "main.py exiting. Error message: " +
                traceback.format_exc(Config.TRACEBACK_LIMIT))
            errors.sendEmail()
            errors.debug("Preparing to exit...")
            sys.exit("Unable to read outdata.conf")

        except:  #unexpected error of some other sort
            errors.error(
                "FATAL: unexpected error in parsing outdata.conf. main.py " +
                "exiting. Error message: " +
                traceback.format_exc(Config.TRACEBACK_LIMIT))
            errors.sendEmail()
            errors.debug("Preparing to exit...")
            sys.exit("Unable to parse outdata.conf")

        self.data = {}  #a dictionary keying label to converted data
        self.unrecognized_labels = []  #initialize error flags/lists:
        self.missing_data = []
        self.to_unix_error = False
        self.temp_backup_error = False
        self.flash_file_error = False
        self.flash_drive_error = False
        self.for_dash_error = False
        open("temp_unix_backup", 'w').close()  #initialize backup file
예제 #8
0
    def send_commands(self):
        """
		Reads files holding all commands for the PIC and sends them.
		Command file should be formatted as <cmd><tab><source>, with
		one command per line.
		"""
        errors.debug("Preparing to send commands to PIC.")
        try:
            with open(Config.COMMAND_FILE_PATH, 'r') as command_file:
                for line in command_file:
                    command = line.split('\t')
                    errors.debug(str(command))
                    if len(command) > 2:
                        self.port.write(command[0].strip())
                        if command[1].strip() == "DASH":
                            errors.info("TS-4200 sent command " + command[0] +
                                        " from source " + command[1].strip() +
                                        " to PIC via serial.")
                        else:
                            errors.debug("Sent command " + command[0] +
                                         " from source " + command[1].strip())
        except:
            if not self.command_error:
                self.command_error = True
                errors.error(
                    "Error in reading and sending commands. Error message: " +
                    traceback.format_exc(Config.TRACEBACK_LIMIT))
        else:
            open(Config.COMMAND_FILE_PATH, 'w').close()
예제 #9
0
 def build_file_for_dash(
         self):  #overwrites the file for dash with raw data.
     errors.debug("Data reader building file of raw data for dash board...")
     with open(
             'picdata.conf.cache', 'r'
     ) as picdata:  #dataoutputter will pick this file up and append converted data to it
         with open('data_for_dash', 'w') as fordash:
             fordash.write(str(time.time()) + '\n')
             for line in picdata:
                 line = line.strip()
                 if line == "" or line[0] == "#":
                     pass
                 elif len(line) > 4 and line[:4] == "STR:":
                     fordash.write("RAW\t" + line[4:].strip() + '\n')
                 else:
                     try:
                         raw = self.get(line)
                     except DataMissingError:
                         raw = "not received"
                     fordash.write(line + '\t' + raw + '\n')
                     #print line + '\t' + raw + '\n'
     errors.debug("Done building raw data file for dash.")
예제 #10
0
	def __init__(self):
		"""
		Constructor for WeatherScheduler. Responsible for initializing
		instances of DataReader and DataOutputter and setting these to
		be used by DataConverters. Also initializes a scheduler from
		python's sched module.
		"""
		self.startup_time = time.time()														#get the current time
		t = "unknown"
		try:
			with open(Config.ONELINE_PATH, 'r') as last_time:
				t = float(last_time.read().split('\t')[0])									#get the last time logged 
		except:
			t = "unknown"

		try:
			downtime = int((self.startup_time - t)/60)										#calculate and alert how long Freya has been down
			errors.info("main.py restarting after " + str(downtime) + " minutes' downtime.")
		except TypeError:
			pass

		errors.debug("WeatherScheduler initializing.")
		self.reader = DataReader()															#initialize a DataReader to handle raw data 
		self.outputter = DataOutputter()													#initialize a DataOutputter to handle converted data
																							#see handleData for details on these
		DataConverters.DataConverter.set_in_out(											#tell all DataConverters to use the objects just created
									reader=self.reader, 
									outputter=self.outputter)			
		self.scheduler = sched.scheduler(time.time, time.sleep)								#create a scheduler to handle the main loop's timing

		self.cycles = 0																		#this counter will be used to tell daily_checks when to run
		self.sched_warning_sent = False 													#remember if a falling-behind-schedule warning has already been sent
		self.endToggle = False 																#this is set to true when a signal is received, and allows the
																							#program to exit gracefully at the end of a cycle
		signal.signal(signal.SIGUSR1, self.end) 											#initialize a signal handler to catch SIGUSR1 and call self.end()
		errors.debug("Set signal handler for SIGUSR1 to " + str(signal.getsignal(signal.SIGUSR1)))
		self.maybe_end()
예제 #11
0
	def run(self):
		"""
		This function waits until safe to get data from PIC, then runs
		the main loop forever, calling other functions as scheduled.
		"""
		still_to_wait = int(Config.WAIT_AT_STARTUP - (time.time() - self.startup_time))		#calculate how much longer to wait
		errors.debug("Waiting " + str(still_to_wait) + " seconds for PIC...")

		for i in range(int(still_to_wait/20)):												#wait, but periodically check if end signal has been received
			for j in range(19):
				time.sleep(1)
			self.maybe_end()

		errors.debug("Entering main loop.")
		self.last_cycle_started = time.time()
		while True:
			errors.debug("____________NEW CYCLE____________")
			errors.sendEmail()
			self.note_running()
			os.environ['TZ'] = 'CST+6'
			time.tzset()
			local_time = time.localtime()
			unix_time = str(time.time())
			year = str(local_time.tm_year)
			month = str(local_time.tm_mon)
			day = str(local_time.tm_mday)
			hour = str(local_time.tm_hour)
			minute = str(local_time.tm_min)
			second = str(local_time.tm_sec)
			clk_source = Config.NULL_VAL
			stardate = Config.NULL_VAL
			future = Config.NULL_VAL
			header = [unix_time, year, month, day, hour, minute, second, clk_source, stardate, future]
			header_1 = [unix_time, year, month, day, hour, minute, second, clk_source, stardate, future]
			header_2 = [unix_time, year, month, day, hour, minute, second, clk_source, stardate, future]
			toggleFile = open(Config.TOGGLE_FILE_PATH, 'r')
			toggle = toggleFile.readline()
			if toggle == '': 
				toggle = 0
			toggleFile.close()
			self.reader.read(header, header_1, int(toggle))
			convert.process_all()
			self.outputter.save(header_2, int(toggle))
			toggleFile = open(Config.TOGGLE_FILE_PATH, 'r')
			last_toggle = int(toggleFile.readline())
			toggleFile.close()
			toggleFile = open(Config.TOGGLE_FILE_PATH, 'w')
			if (last_toggle == 1 and int(toggle) == 0):
				toggleFile.write('1')
			else:
				toggleFile.write('0')
			toggleFile.close()  
			self.reader.send_commands()
			self.daily_checks()	
			self.finish_cycle()
			self.scheduler.run()
예제 #12
0
	def finish_cycle(self):
		"""Called at the end of a cycle to wrap up"""
		self.maybe_end()																	#see above
		time_to_sleep = self.last_cycle_started + 29.9787 - time.time()						#calculate time to sleep. 19.9787 is 20s minus the average 
																							#time it takes to queue the next cycle
		if time_to_sleep < Config.BEHIND_SCHEDULE_WARNING:									#if behind schedule, send an alert and don't sleep
			if not self.sched_warning_sent:
				errors.info("main.py is falling behind schedule. Last cycle ended " + str(time_to_sleep)[1:] + " seconds late. Corrective action recommended.")
				self.sched_warning_sent = True
			else:
				errors.debug("Not sleeping before next cycle, already behind " +str(time_to_sleep)[1:]+ " seconds.")
		elif time_to_sleep < 0:
			errors.debug("Not sleeping before next cycle, already behind " +str(time_to_sleep)[1:]+ " seconds.")
		else:
			errors.debug("Seconds to next cycle: " + str(time_to_sleep))					#sleep until time for next cycle
			time.sleep(time_to_sleep)
		self.last_cycle_started = time.time()
예제 #13
0
def reset_all_flags(
):  #resets flags for all converters. called from main.py daily.
    debug(
        "reset_all_flags called; resetting all data converter error flags...")
    for converter in all_converters:
        converter.reset_flags()
예제 #14
0
	def end(self, signum, frame):															#this method catches the SIGUSR1 signal sent by end.sh and
		errors.debug("Received SIGUSR1.")													#sets endToggle to true. endToggle will be checked periodically, and
		self.endToggle = True																#if it is true the program ends (see above).
예제 #15
0
 def send(self, cmd):
     """Sends string cmd to PIC via serial connection."""  #flush input so that input doesn't build up in serial port --
     self.port.write(cmd)  #we want only data sent in response to S
     errors.debug("Sent " + cmd + " to PIC.")
예제 #16
0
	def note_running(self):
		"""Leave a timestamp in a file so GUI knows Freya is running"""
		with open("board_is_running", 'w') as b:											#write the current time to a file
			b.write(str(time.time()))
		errors.debug("Updated timestamp for dash.")
예제 #17
0
    def read(self, header, header_1, toggle):
        """
		Reads strings of raw data from serial port and checks them for
		errors before saving them in a dictionary. The strings that make
		it through this method are guaranteed to have the right ID and 
		length, but any given piece of data could conceivably be missing ("").
		Checking that data exist is the job of get().
		"""
        raw_data_list = header
        raw_array_data_list = header_1
        string_list = []
        self.dataStrings = {}  #clearing data
        errors.debug("read() called, getting data...")
        strings = []
        print str(
            self.numStrings()) + " from read() in DataReader"  #ENTER LOOP
        self.port.write("SS")
        string_B = self.port.readline(size=None, eol='\r')
        time.sleep(1.1)
        string_B = string_B.split('\t')
        string_list.append(string_B)
        self.port.write("QQ")
        self.port.write("11")
        time.sleep(7)
        string_1 = self.port.readline(size=None, eol='\r')
        time.sleep(1.1)
        string_1 = string_1.split('\t')
        string_list.append(string_1)
        self.port.write("22")
        string_2 = self.port.readline(size=None, eol='\r')
        time.sleep(1.1)
        string_2 = string_2.split('\t')
        string_list.append(string_2)
        self.port.write("33")
        string_3 = self.port.readline(size=None, eol='\r')
        time.sleep(1.1)
        string_3 = string_3.split('\t')
        string_list.append(string_3)
        self.port.write("44")
        string_4 = self.port.readline(size=None, eol='\r')
        time.sleep(1.1)
        string_4 = string_4.split('\t')
        string_list.append(string_4)
        for i in range(len(string_list)):
            string = string_list[i]
            badstring = 1
            if string == "":  #if data read is empty...
                self.totalEmptyStrings += 1  #increment the relevant counters, and
                self.consecutiveEmptyStrings += 1
                errors.debug("Received empty string from PIC.")
                with open("pic_status", 'w') as pic_status:
                    pic_status.write("0")
                if self.consecutiveEmptyStrings == Config.MISSED_CONSECUTIVE_STRING_WARNING:  #send a warning if necessary
                    downtime = int(
                        (self.consecutiveEmptyStrings / 3) / self.numStrings())
                    errors.error("PIC has been unresponsive for " +
                                 str(downtime) + " minutes.")
            else:  #if string is not empty...
                with open("pic_status", 'w') as pic_status:
                    pic_status.write("1")
                if self.consecutiveEmptyStrings > Config.MISSED_CONSECUTIVE_STRING_WARNING:  #send a notification that PIC is responsive, if necessary
                    errors.error("Received string from PIC after " +
                                 str(self.consecutiveEmptyStrings) +
                                 " consecutive missed strings.")
                self.consecutiveEmptyStrings = 0  #reset consecutiveEmptyStrings counter												#make the string into a list to better manipulate it
            stringID = string[0]  #save the ID (the first item in the list)
            string = string[
                1:]  #BUILD DATA STRING and check for missing data:												#put each datum into a list
            print "self.expected_strings", self.expected_strings  #remove the ID from the string
            if stringID not in self.expected_strings:  #if the ID is not recognized...
                if not self.PICStringIDErrorState:  #notify as appropriate
                    errors.error(
                        "Received unexpected string from PIC starting with " +
                        stringID +
                        ". Assume error continues until intervention. Data will be lost "
                        +
                        "if strings of the expected format are not received.")
                else:
                    errors.debug(
                        "Received bad string from PIC starting with " +
                        stringID + ".")
                self.PICStringIDErrorState = True  #and raise error flag
            else:  #if ID is recognized...
                errors.debug("String of ID " + stringID + " found.")
                expectedLength = self.expected_strings[stringID]
                if len(
                        string
                ) != expectedLength:  #check if it is the expected length
                    if not self.PICFormatErrorState:  #if not, notify as appropriate
                        errors.info(
                            "Received bad string from PIC: " +
                            str(len(string)) + " fields instead of " +
                            str(expectedLength) + " fields in string " +
                            stringID +
                            ". Assume error continues until intervention. Data will be lost "
                            +
                            "if strings of the expected format are not received. Any strings not "
                            +
                            "conforming to expected format can not be processed."
                        )
                    else:
                        errors.debug("Received bad string from PIC: " +
                                     str(len(string)) + " fields instead of " +
                                     str(expectedLength) + " fields.")
                    self.PICFormatErrorState = True  #and raise error flag
                else:  #if it is the expected length, then accept it
                    errors.debug("String accepted.")
                    self.dataStrings[
                        stringID] = string  #add it to dictionary of data
                    badstring = 0  #mark it as a good string

            self.totalBadStrings += badstring
        string_B = string_B[1:]
        string_1 = string_1[1:]
        string_2 = string_2[1:]
        string_3 = string_3[1:]
        string_4 = string_4[1:]
        len_string_1 = len(string_1)
        len_string_B = len(string_B)
        len_string_2 = len(string_2)
        len_string_3 = len(string_3)
        len_string_4 = len(string_4)
        exp_len_string_1 = self.expected_strings['1']
        exp_len_string_B = self.expected_strings['B']
        exp_len_string_2 = self.expected_strings['2']
        exp_len_string_3 = self.expected_strings['3']
        exp_len_string_4 = self.expected_strings['4']
        if (len_string_1 == 0):
            for i in range(exp_len_string_1):
                string_1.append(str(Config.ERROR_VAL))
        if (len_string_B == 0):
            for i in range(exp_len_string_B):
                string_B.append(str(Config.ERROR_VAL))
        if (len_string_2 == 0):
            for i in range(exp_len_string_2):
                string_2.append(str(Config.ERROR_VAL))
        if (len_string_3 == 0):
            for i in range(exp_len_string_3):
                string_3.append(str(Config.ERROR_VAL))
        if (len_string_4 == 0):
            for i in range(exp_len_string_4):
                string_4.append(str(Config.ERROR_VAL))
        for item in string_1:
            raw_data_list.append(item.strip())
        for item in string_B:
            raw_data_list.append(item.strip())
        for item in string_2:
            raw_array_data_list.append(item.strip())
        for item in string_3:
            raw_array_data_list.append(item.strip())
        for item in string_4:
            raw_array_data_list.append(
                item.strip()
            )  #add to counter if string was not good																					#and repeat
        raw_data_string = "\t".join(raw_data_list) + '\n'
        raw_array_data_string = "\t".join(raw_array_data_list) + '\n'
        if (not os.path.exists(Config.CUR_BACKUP_PATH)):
            os.makedirs(Config.CUR_BACKUP_PATH)
        if os.path.ismount(Config.FLASH_BACKUP_DIREC_PATH):
            try:
                errors.debug("Attempting to write rawdata backup")
                with open(
                        Config.RAW_DATA_BACKUP_PATH,
                        'a') as raw_data_backup:  #actually write data to file
                    raw_data_backup.write(raw_data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except:
                errors.debug("Copy failed.")
            raw_data_backup.close()
            try:
                errors.debug("Attempting to write raw array data backup")
                with open(
                        Config.RAW_ARRAY_DATA_BACKUP_PATH, 'a'
                ) as raw_array_data_backup:  #actually write data to file
                    raw_array_data_backup.write(raw_array_data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except:
                errors.debug("Copy failed.")
        raw_array_data_backup.close()
        if (toggle == 1):
            try:
                errors.debug("Attempting to write rawdata")
                with open(Config.RAW_DATA_FILE_PATH,
                          'w') as raw_data:  #actually write data to file
                    raw_data.write(raw_data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except:
                errors.debug("Copy failed.")
            raw_data.close()
            try:
                errors.debug("Attempting to write raw array data")
                with open(Config.RAW_ARRAY_DATA_FILE_PATH,
                          'w') as raw_array_data:  #actually write data to file
                    raw_array_data.write(raw_array_data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except:
                errors.debug("Copy failed.")
            raw_array_data.close()
        if (toggle == 0):
            try:
                errors.debug("Attempting to write rawdata")
                with open(Config.RAW_DATA_FILE_PATH,
                          'a') as raw_data:  #actually write data to file
                    raw_data.write(raw_data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except:
                errors.debug("Copy failed.")
            raw_data.close()
            try:
                errors.debug("Attempting to write raw array data")
                with open(Config.RAW_ARRAY_DATA_FILE_PATH,
                          'a') as raw_array_data:  #actually write data to file
                    raw_array_data.write(raw_array_data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except:
                errors.debug("Copy failed.")
            raw_array_data.close()  #EXIT LOOP
        for stringID in self.expected_strings:  #check that each expected string was received
            if stringID not in self.dataStrings:  #if a string wasn't read,
                if stringID not in self.badFormatErrors:  #and isn't already broken,
                    errors.error(
                        "Did not receive full string " + stringID +
                        " from PIC. " +  #send an alert
                        "Assume error continues until otherwise notified. No data from "
                        + stringID + " available.")
                    self.badFormatErrors.append(
                        stringID)  #and add it to the list of broken strings
                else:
                    errors.debug("Did not find string " + stringID + " again.")
            else:  #if a string was read, make sure it isn't in the list of broken strings
                try:
                    self.badFormatErrors.remove(
                        stringID)  #alert that it is working again
                    errors.error(
                        "Received previously missing string " + stringID +
                        ". Assume problem solved until notified otherwise.")
                except:
                    pass
        errors.debug("Done reading and storing data.")
예제 #18
0
    def __init__(self):
        """
		Constructor for DataReader. Responsible for initializing locations,
		a dictionary keying (string, index) by field label, from picdata.conf.
		If this fails, method will raise SystemExit. Also opens serial connection 
		as configured in Config.py. If connection fails at first, method will 
		continue attempting indefinitely.
		"""
        errors.debug("DataReader initializing...")
        self.locations = {
        }  #this code reads picdata.conf and turns it into a dictionary,
        index = 0  #keyed by field label holding a tuple of string name and index in string (from 0):
        current_string = None  #in essence, the dictionary created here asks for the string's label and gives its location.
        #it will be used to tell the DataReader where to look for data that is requested
        self.expected_strings = {
        }  #expected_strings keys each string expected to its length
        errors.debug("Attempting to parse picdata.")
        try:
            copyfile('picdata.conf', 'picdata.conf.cache')
            with open(
                    'picdata.conf.cache',
                    'r') as picdata:  #open the file containing expected format
                for line in picdata:  #iterate though each line
                    line = line.strip(
                        '\n')  #clean the line of return characters
                    if line != '' and line[
                            0] != "#":  #skip empty lines and comments
                        if len(
                                line
                        ) >= 4 and line[:4] == "STR:":  #if "STR:" tag is present, register the start of a new string
                            index = 0  #start counting index from zero
                            current_string = line[4:].strip(
                            )  #save string as current string
                            errors.debug("Registered string " + current_string)
                        else:  #if "STR:" tag is not present, the line must contain the name of a field
                            if line in self.locations:
                                errors.info(
                                    "Warning: picdata.conf contains label " +
                                    line +
                                    " multiple times. Only the last instance will be kept."
                                )
                            if current_string is None:
                                errors.info(
                                    "Warning: picdata.conf is improperly formatted, "
                                    + "contains label without string header.")
                            else:
                                self.locations[line] = (
                                    current_string, index
                                )  #add an entry to the dictionary holding the string it is in and the index in that string
                                index += 1  #increment the index for next time
                        self.expected_strings[current_string] = index
            errors.debug("Parsed picdata.conf successfully.")

            for label in self.locations:  ################################
                print label, self.locations[
                    label], "\n"  ################################
            print "self.expected_strings ->", self.expected_strings

            #in the case of errors, send a message and then exit the program:
        except IOError:  #error in finding or reading file (if thrown, most likely picdata.conf does not exist)
            errors.error(
                "FATAL: DataReader unable to read picdata.conf. " +
                "TS-4200 will not be able to interpret strings received from PIC until fixed. "
                + "main.py exiting. Error message: " +
                traceback.format_exc(Config.TRACEBACK_LIMIT))
            errors.sendEmail()
            errors.debug("Preparing to exit...")
            sys.exit("Unable to read picdata.conf")
        except (
                IndexError, KeyError
        ):  #error in adding entry or slicing string (very unlikely, this is here just in case)
            errors.error(
                "FATAL: DataReader unable to parse picdata.conf. " +
                "Error is either in parser or in format of picdata.conf. main.py "
                + "exiting. Error message: " +
                traceback.format_exc(Config.TRACEBACK_LIMIT))
            errors.sendEmail()
            errors.debug("Preparing to exit...")
            sys.exit("Unable to parse picdata.conf")
        except:  #unexpected error of some other sort
            errors.error(
                "FATAL: unexpected error in parsing picdata.conf. main.py " +
                "exiting. Error message: " +
                traceback.format_exc(Config.TRACEBACK_LIMIT))
            errors.sendEmail()
            errors.debug("Preparing to exit...")
            sys.exit("Unable to parse picdata.conf")

        self.connectionFailures = 0
        while True:  #try to establish connection to serial port:
            try:
                errors.debug("Attempting serial port connection...")
                self.port = serial.Serial(  #create a Serial object to represent the port
                    port=Config.PORT_NUM,
                    baudrate=Config.BAUD_RATE,
                    timeout=Config.PORT_TIMEOUT)
                if self.connectionFailures > 1:  #alert to success if connection has failed previously
                    errors.sendEmail(
                        message=
                        "Serial connection successful, initialization continuing.",
                        subject="TS-4200 Serial Connection Successful")
                errors.log.error("Serial connection successful.")
                break  #exit loop if successful
            except serial.SerialException:  #at two fails, log and send an email
                self.connectionFailures += 1
                if self.connectionFailures == 2 or self.connectionFailures % 4320 == 0:  #at two fails or every 6 hours, log and send an email
                    errors.sendEmail(
                        message="Failed to connect to serial port. " +
                        "TS-4200 not functional until further notice. " +
                        "Attempts to connect will continue indefinitely. " +
                        "Error message: " +
                        traceback.format_exc(Config.TRACEBACK_LIMIT),
                        subject="TS-4200 Failed to Connect to Serial Port")
                errors.debug("Serial connection failed.")
                time.sleep(
                    5
                )  #not much point in running the rest of the program without a serial connection, 																					#so try until success																					#initialize various flags to keep track of errors:
        self.consecutiveEmptyStrings = 0  #number of strings consecutively not received from PIC
        self.totalEmptyStrings = 0  #total number of strings not received since start up or last reset
        self.PICStringIDErrorState = False  #whether or not there is an outstanding unrecognized string coming from PIC
        self.PICFormatErrorState = False  #whether or not there is an string of the wrong length coming from PIC
        #note that the above two will mask other errors of their sort until the first is fixed
        #(i.e., two unrecognized strings are sent repeatedly but only one is reported at first)
        self.totalBadStrings = 0  #number of received strings since start up or reset for which there was some error
        self.badFormatErrors = [
        ]  #hold every field/string requested by DataConverters that was not found

        self.dataStrings = {}  #create empty dictionary to hold data
        open(Config.COMMAND_FILE_PATH, 'a').close()
        self.command_error = False
        errors.debug("DataReader initialization completed.")
예제 #19
0
	def trigger(self,triggerer,objects):
		if self.triggerCheck():
			self.timeLeft = self.time
			errors.debug(self.getID()+" triggered.")
			self.triggered = True
예제 #20
0
    def save(self, header, toggle):
        """
		Formats all received converted data and saves it to the 
		appropriate configuration of files. Clears all data so outputter
		is available to receive a new batch.
		"""
        data_list = header  #BUILD DATA STRING and check for missing data:
        for label in self.format:  #for each expected piece of data
            try:
                data = str(self.data[label])  #request it from self.data
            except KeyError:  #if it is not found, send an alert
                if label not in self.missing_data:  #note that this alert applies only to data not sent at all -- data noted as missing earlier will
                    errors.error(
                        "DataOutputter missing data for label " + label
                        +  #have been replaced by an error value and so will not throw this error.
                        ". Probable cause: no data converter passes data to outputter."
                        +  #this error should just catch coding mistakes (such as a piece of expected data not being passed to
                        " Problem will continue until fixed."
                    )  #the outputter for whatever reason)
                    self.missing_data.append(label)
                data = str(
                    Config.ERROR_VAL)  #...and replace it with the error value
            data_list.append(data)  #put each datum into a list
        data_string = "\t".join(data_list) + '\n'  #turn the list into a string
        self.data = {}
        if (not os.path.exists(Config.CUR_BACKUP_PATH)):
            os.makedirs(Config.CUR_BACKUP_PATH)  #clear data

        try:
            errors.debug("Attempting to write oneline")
            with open(Config.ONE_LINE_FILE_PATH,
                      'w') as one_line:  #actually write data to file
                one_line.write(data_string)
            errors.debug("...write successful.")
            self.to_unix_error = False
        except:
            errors.debug("Copy failed.")
        if (toggle == 1):  #WRITE TO 2UNIX:
            try:  #this try block copies over backed up data to 2UNIX in case of interference or failure
                errors.debug("Copying temp_backup over to 2UNIX..."
                             )  #this is a plan C, very unlikely to be needed.
                with open("temp_unix_backup", 'r') as backup:
                    missing_data = backup.read()
                with open(Config.TO_UNIX_FILE_PATH, 'w') as to_unix:
                    to_unix.write(missing_data)
                open("temp_unix_backup", "w").close()
            except:
                errors.debug("Copy failed.")

            try:
                errors.debug("Attempting to write to 2UNIX...")
                with open(Config.TO_UNIX_FILE_PATH,
                          'w') as to_unix:  #actually write data to file
                    to_unix.write(data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except IOError:
                time.sleep(.1)  #if it fails, wait and try again
                errors.debug("...write failed, trying again.")
                try:
                    with open(Config.TO_UNIX_FILE_PATH,
                              'w') as to_unix:  #try to write again
                        to_unix.write(data_string)
                        errors.debug("Second write successful.")
                        self.to_unix_error = False
                except IOError:  #if that fails, put data in a backup
                    errors.debug("Second write failed.")
                    if not self.to_unix_error:
                        errors.error(
                            "Unable to write to file for database. Storing unsent data in a temporary backup."
                        )
                        self.to_unix_error = True
                    try:
                        with open("temp_unix_backup", 'w') as backup:
                            backup.write(data_string)
                        errors.debug("Wrote data to backup.")
                        self.temp_backup_error = False
                    except:  #if the backup fails, not much more that can be done
                        if not self.temp_backup_error:
                            errors.error(
                                "Write to temporary backup failed. Data will not be written to 2UNIX."
                            )
                            self.temp_backup_error = True
                    else:
                        errors.debug("Write to 2UNIX failed again.")
        if (toggle == 0):  #WRITE TO 2UNIX:
            try:  #this try block copies over backed up data to 2UNIX in case of interference or failure
                errors.debug("Copying temp_backup over to 2UNIX..."
                             )  #this is a plan C, very unlikely to be needed.
                with open("temp_unix_backup", 'r') as backup:
                    missing_data = backup.read()
                with open(Config.TO_UNIX_FILE_PATH, 'a') as to_unix:
                    to_unix.write(missing_data)
                open("temp_unix_backup", "w").close()
            except:
                errors.debug("Copy failed.")

            try:
                errors.debug("Attempting to write to 2UNIX...")
                with open(Config.TO_UNIX_FILE_PATH,
                          'a') as to_unix:  #actually write data to file
                    to_unix.write(data_string)
                errors.debug("...write successful.")
                self.to_unix_error = False
            except IOError:
                time.sleep(.1)  #if it fails, wait and try again
                errors.debug("...write failed, trying again.")
                try:
                    with open(Config.TO_UNIX_FILE_PATH,
                              'a') as to_unix:  #try to write again
                        to_unix.write(data_string)
                        errors.debug("Second write successful.")
                        self.to_unix_error = False
                except IOError:  #if that fails, put data in a backup
                    errors.debug("Second write failed.")
                    if not self.to_unix_error:
                        errors.error(
                            "Unable to write to file for database. Storing unsent data in a temporary backup."
                        )
                        self.to_unix_error = True
                    try:
                        with open("temp_unix_backup", 'a') as backup:
                            backup.write(data_string)
                        errors.debug("Wrote data to backup.")
                        self.temp_backup_error = False
                    except:  #if the backup fails, not much more that can be done
                        if not self.temp_backup_error:
                            errors.error(
                                "Write to temporary backup failed. Data will not be written to 2UNIX."
                            )
                            self.temp_backup_error = True
                    else:
                        errors.debug("Write to 2UNIX failed again.")

                        #COPY FROM LOCAL TO FLASH DRIVE BACKUP (in case of flash drive coming back online)
        if os.path.ismount(
                Config.FLASH_BACKUP_DIREC_PATH
        ) and not self.flash_file_error:  #checking whether drive is mounted so that code does not save to local file at same path
            try:
                errors.debug(
                    "Copying local backup to flash."
                )  #try copying local backup to flash drive. if no data in local backup, just append nothing
                with open(Config.LOCAL_BACKUP_FILE_PATH,
                          'r') as local:  #open and read data from local backup
                    forFlash = local.read()
                with open(Config.TO_UNIX_BACKUP_PATH,
                          'a') as flash:  #append data to flash backup
                    flash.write(forFlash)
                open(Config.LOCAL_BACKUP_FILE_PATH,
                     'w').close()  #clear local backup if successful
                self.flash_file_error = False
            except:
                if not self.flash_file_error:
                    errors.info(
                        "Copy from local to flash failed, but flash drive mounted. "
                        +
                        "Beware discontinuity in data starting around current time. "
                        + "Error message: " +
                        traceback.format_exc(Config.TRACEBACK_LIMIT))
                os.system("sudo umount /dev/sda1")  #unmount flash drive
                self.flash_file_error = True
        else:
            errors.debug(
                "Flash unmounted, copy from local to flash not attempted.")

            #BACKUP DATA ON FLASH DRIVE
        if os.path.ismount(
                Config.FLASH_BACKUP_DIREC_PATH):  #if flash drive is mounted:
            try:  #try writing data to backup on flash drive
                with open(Config.TO_UNIX_BACKUP_PATH,
                          'a') as flash:  #open file and write data
                    flash.write(data_string)
                    if self.flash_drive_error:  #if it didn't work last time, alert that it is working
                        errors.error(
                            "Write to flash drive successful -- flash backup online."
                        )
                        self.flash_drive_error = False
                    else:
                        errors.debug(
                            "Data written to flash drive successfully.")
            except:  #if failure, alert as appropriate and write data to local backup instead
                if not self.flash_drive_error:
                    errors.error(
                        "Flash drive mounted, but unable to write to flash backup. "
                        + "Error message: " +
                        traceback.format_exc(Config.TRACEBACK_LIMIT))
                self.flash_drive_error = True
        else:
            if not self.flash_drive_error:
                errors.error(
                    "Flash drive unmounted. TS-4200 unable to write to backup file on flash drive. "
                    +
                    "Data diverted to local filesystem backup until notified otherwise."
                )
            else:
                errors.debug(
                    "Flash drive still unmounted, diverting data to local backup."
                )
            self.flash_drive_error = True

            #IF FLASH DRIVE UNMOUNTED, WRITE TEMPORARILY TO LOCAL BACKUP
            try:
                with open(Config.LOCAL_BACKUP_FILE_PATH,
                          'a') as local:  #open and write data to local backup
                    local.write(data_string)
            except:
                errors.error(
                    "BACKING UP FAILED: unable to write to either flash " +
                    "or local backup. Error message: " +
                    traceback.format_exc(Config.TRACEBACK_LIMIT))

        self.data_list = data_list
예제 #21
0
    def get(self, label):
        """
		Given a label, returns that label's stored data as a string. If no
		such label is found in the given format or if the corresponding data 
		point is not found in received data, registers an error message.
		Errors are stored in a list as the name (label, stringID, or ID+index)
		of the missing location. If a location is already in the list, email 
		will not be resent. These errors are expected to handle cases of
		typos in picdata.conf or data converting code, missing strings, and
		so on. This method does not check type -- calling methods get either
		the raw data exactly as received (as a string) or Config.ERROR_VAL. 
		Be sure NOT to use this method to request the name of a string (eg, B or T).
		"""
        try:
            tup = self.locations[
                label]  #try to retrieve information about the requested field from self.locations
        except KeyError:  #if info retrieval throws error, notify...
            if label not in self.badFormatErrors:
                errors.error(
                    "NO RAW DATA ERROR: data for '" + label +
                    "' requested, but no such " +
                    "label found. Either label not added to picdata.conf or misspelled "
                    + "somewhere. Error message: " +
                    traceback.format_exc(Config.TRACEBACK_LIMIT) +
                    "Assume error continues until otherwise notified.")
                self.badFormatErrors.append(
                    label)  #...and add to list of errors...
            #errors.debug("get called but data for " + label + " not returned.")
            raise DataMissingError(
                label
            )  #...and return None, so calling method knows there is no data
        else:
            try:
                self.badFormatErrors.remove(
                    label
                )  #if that succeeds, try to remove label from the list of missing data...
                errors.debug(
                    "get called on " + label +
                    " successful, removing error flag."
                )  #this little error sub-system is too subtle for comments -- see documentation
            except:
                pass  #...but don't worry if it wasn't there in the first place

        try:  #using the information from self.locations,
            stringID = tup[0]
            index = tup[1]
            data = self.dataStrings[stringID][
                index]  #try to find data for the requested label
            try:  #if that succeeds, remove location from list of missing
                self.badFormatErrors.remove(stringID + str(index))
                errors.debug("get called on " + stringID + str(index) +
                             " successfully, removing error flag.")
            except:
                pass
            try:  #if that succeeds, remove stringID from list of missing
                self.badFormatErrors.remove(stringID)
                errors.debug("get called on member of string " + stringID +
                             " successfully, removing error flag.")
            except:
                pass
        except KeyError:  #handle errors. these will only be called if there is a missing string or
            if stringID not in self.badFormatErrors:  #some other corruption of data betweed the calling of read() and get()
                errors.error(
                    "String '" + stringID +
                    "' not found among received data: mismatch " +
                    "between picdata.conf and requested data, probably. Error message: "
                    + traceback.format_exc(Config.TRACEBACK_LIMIT) +
                    " Assume error continues until " + "otherwise notified.")
                self.badFormatErrors.append(stringID)
            errors.debug("get called but data for " + label + " not returned.")
            raise DataMissingError(label)
        except IndexError:  #this particular case should hardly ever be reached, but is here for completeness.
            if stringID + str(index) not in self.badFormatErrors:
                errors.error(
                    "Data field " + stringID + str(index) +
                    " not found among received data: " +
                    "mismatch between picdata.conf and requested data. Error message: "
                    + traceback.format_exc(Config.TRACEBACK_LIMIT) +
                    " Assume error continues until " + "otherwise notified.")
                self.badFormatErrors.append(stringID + str(index))
            errors.debug("get called but data for " + label + " not returned.")
            raise DataMissingError(label)
        return data  #return data as a string. methods calling get() will be responsible for type-checking.
예제 #22
0
def process_all(
):  #this function loops through all converters and calls safe_process on them.
    debug("process_all called; calling safe_process of all data converters...")
    for converter in all_converters:  #it is called from main.py after data is read.
        converter.safe_process(
        )  #safe_process (defined in DataConverters.py) handles getting raw data from the reader, converting it, responding to
예제 #23
0
def loadXML(xmlPath,level,GameEngine,GraphicEngine):
	errors.info("Loading level: "+level)

	try:
		filer = open(xmlPath,"r")
	except IOError:
		errors.critical("Level file not found.")
		exit()

	lines = filer.readlines()

	started=False

	levelData = []

	for i in range(len(lines)):	#Strip Tabs and New Lines
		lines[i] = lines[i].lstrip("\t").rstrip("\n")

	for line in lines:	#Extract Level Data
		if not started:
			if line == "<Level "+level+">":
				started=True
			continue
		if line == "</Level>":
			break
		levelData.append(line)

	Name=None
	BG = None
	Mask=None
	Enemies=None
	BattleBG=None
	BattleFBG=None
	Triggers = []
	GameObjects = []
	NPCs = []
	i = 0

	while i < len(levelData):	#Isolate Triggers, NPCs, and GameObjects (GraphicObjects must be dealt with immediately because they are contained within GameObjects)
		temp = {}
		if levelData[i].startswith("<LevelName>"):
			Name=levelData[i].lstrip("<LevelName").lstrip(">").rstrip("/LevelName>").rstrip("<")
		elif levelData[i].startswith("<Background>"):
			BG=levelData[i].lstrip("<Background").lstrip(">").rstrip("/Background>").rstrip("<")
		elif levelData[i].startswith("<Mask>"):
			Mask=levelData[i].lstrip("<Mask").lstrip(">").rstrip("/Mask>").rstrip("<")
		elif levelData[i].startswith("<Enemies>"):
			Enemies = json.loads(levelData[i].lstrip("<Enemies").lstrip(">").rstrip("/Enemies>").rstrip("<"))
		elif levelData[i].startswith("<BattleBG>"):
			BattleBG = json.loads(levelData[i].lstrip("<BattleBG").lstrip(">").rstrip("/BattleBG>").rstrip("<"))
		elif levelData[i]=="<Trigger>":
			n=1
			while levelData[i+n]!="</Trigger>":
				key = levelData[i+n][1:levelData[i+n].find(">")]
				value = levelData[i+n][levelData[i+n].find(">")+1:levelData[i+n].find("<",levelData[i+n].find(">"))]
				temp[key]=json.loads(value)
				n+=1
			Triggers.append(temp)
			i+=n
		elif levelData[i].startswith("<GameObject"):
			path = levelData[i].lstrip("<GameObject").rstrip(">").lstrip(" ").split(" ")[0]
			if len(levelData[i].lstrip("<GameObject").rstrip(">").lstrip(" ").split(" "))>1:
				objectName = levelData[i].lstrip("<GameObject").rstrip(">").lstrip(" ").split(" ")[1]
			if path != "":
				tempFiler = file(config.AssetPath+path,"r")
				lines = tempFiler.readlines()
				started=False
				for j in range(len(lines)):	#Strip Tabs and New Lines
					lines[j] = lines[j].lstrip("\t").rstrip("\n")
				j=1
				for line in lines:	#Extract Level Data
					if not started:
						if line == "<GameObject "+objectName+">":
							started=True
						continue
					if line == "</GameObject>":
						break
					levelData.insert(i+j,line)
					j+=1

				#for line in levelData:
				#	print line

			temp["graphicObject"] = {}
			n=1
			while levelData[i+n]!="</GameObject>":
				key = levelData[i+n][1:levelData[i+n].find(">")]
				if key == "Mask":
					n+=1
					temp["mask"] = {}
					while levelData[i+n]!="</Mask>":
						state = levelData[i+n][7:levelData[i+n].find(">")]
						temp["mask"][state] = json.loads(levelData[i+n][levelData[i+n].find(">")+1:levelData[i+n].rfind("<")])
						n+=1
					n+=1
				elif key == "GraphicObject":
					if "animations" not in temp["graphicObject"]:
						temp["graphicObject"]["animations"] = {}
					n+=1
					while levelData[i+n]!="</GraphicObject>":
						if levelData[i+n].startswith("<State"):
							state = levelData[i+n][7:levelData[i+n].find(">")]
							temp["graphicObject"]["animations"][state] = [None,None,None,None]
							n+=1
							while levelData[i+n]!="</State>":
								#Retrieve Direction
								dire = int(levelData[i+n][11:levelData[i+n].find(">")])
								xml = levelData[i+n][levelData[i+n].find(">")+1:levelData[i+n].rfind("<")]
								if dire == 0:
									temp["graphicObject"]["animations"][state][dire] = loadAnimation(xml,state+"N")
								elif dire == 1:
									temp["graphicObject"]["animations"][state][dire] = loadAnimation(xml,state+"E")
								elif dire == 2:
									temp["graphicObject"]["animations"][state][dire] = loadAnimation(xml,state+"S")
								elif dire == 3:
									temp["graphicObject"]["animations"][state][dire] = loadAnimation(xml,state+"W")
								n+=1
							n+=1
						else:
							key = levelData[i+n][levelData[i+n].find("<")+1:levelData[i+n].find(">")]
							value = levelData[i+n][levelData[i+n].find(">")+1:levelData[i+n].rfind("<")]
							temp["graphicObject"][key] = json.loads(value)
							n+=1
					n+=1
				else:
					value = levelData[i+n][levelData[i+n].find(">")+1:levelData[i+n].find("<",levelData[i+n].find(">"))]
					temp[key[0].lower()+key[1:]]=json.loads(value)
					n+=1
			GameObjects.append(temp)
			i+=n
		elif levelData[i].startswith("<NPC"):
			path = levelData[i].lstrip("<NPC").rstrip(">").lstrip(" ").split(" ")[0]
			if len(levelData[i].lstrip("<NPC").rstrip(">").lstrip(" ").split(" "))>1:
				objectName = levelData[i].lstrip("<GameObject").rstrip(">").lstrip(" ").split(" ")[1]
			if path != "":
				tempFiler = file(config.AssetPath+path,"r")
				lines = tempFiler.readlines()
				started=False
				for j in range(len(lines)):	#Strip Tabs and New Lines
					lines[j] = lines[j].lstrip("\t").rstrip("\n")
				j=1
				for line in lines:	#Extract Level Data
					if not started:
						if line == "<NPC "+objectName+">":
							started=True
						continue
					if line == "</NPC>":
						break
					levelData.insert(i+j,line)
					j+=1

			n=1
			while levelData[i+n]!="</NPC>":
				key = levelData[i+n][1:levelData[i+n].find(">")]
				value = levelData[i+n][levelData[i+n].find(">")+1:levelData[i+n].find("<",levelData[i+n].find(">"))]
				if key == "Dialog":
					if value != "null":
						dialog=open(config.AssetPath+value,"r")
						lines=dialog.readlines()
						dialog=""
						for line in lines:
							dialog+=line.rstrip("\n")
						dialog.replace("\t","")
						temp["Dialog"]=json.loads(dialog)
					else:
						temp["Dialog"]=None
				elif key == "AnimeXML":
					temp["AnimeXML"]=value
				elif key == "Icon":
					if value=="null":
						temp["Icon"]=None
					else:
						temp["Icon"]=value
				else:
					temp[key]=json.loads(value)
				n+=1
			NPCs.append(temp)
			i+=1
		i+=1
	if Name == None:
		errors.warning("Level has no Name attribute.")
		Name = "Unknown Area"
	GraphicEngine.setLevelName(Name)
	if BG == None:
		errors.error("Level has no Background attribute.")
	else:
		try:
			GraphicEngine.setBackground(pygame.image.load(config.AssetPath+BG).convert())
		except pygame.error:
			errors.error("Unable to load level background.")
	if Mask == None:
		errors.info("Level has no Mask attribute.")
	else:
		try:
			GameEngine.setMask(pygame.image.load(config.AssetPath+Mask).convert())
		except pygame.error:
			errors.error("Unable to load level mask.")
	if Enemies != None and len(Enemies)>0:
		if BattleBG == None or len(BattleBG) == 0:
			errors.info("No battle backgrounds specified for this level.")
		else:
#			for i in xrange(len(BattleBG)):
#				for j in range(len(BattleBG[i])):
#					if BattleBG[i][j] != None:
#						try:
#							BattleBG[i][j] = pygame.image.load(BattleBG[i][j]).convert_alpha()
#						except pygame.error:
#							errors.error("Unable to load battle background for this level.")
#							BattleBG[i][j] = None
			GameEngine.setBattleBG(BattleBG)
			GameEngine.setEnemies(Enemies)
	else:
		GameEngine.setBattleBG([])
		GameEngine.setEnemies([])

	for trigger in Triggers:
		errors.debug("Adding "+trigger["Id"]+" trigger.")
		# Should probably be using a factory...
		if "Area" in trigger.keys() and trigger["Area"]!=None:
			trigger["Area"] = pygame.rect.Rect(trigger["Area"])
		if trigger["Effect"]=="State Set":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.StateSetTrigger(**trigger))
		elif trigger["Effect"]=="State Toggle":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.StateToggleTrigger(**trigger))
		elif trigger["Effect"]=="Area Change":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.AreaChangeTrigger(**trigger))
		elif trigger["Effect"]=="SBSC":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.SBSCTrigger(**trigger))
		elif trigger["Effect"]=="TBSC":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.TBSCTrigger(**trigger))
		elif trigger["Effect"]=="Battle":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.BattleTrigger(**trigger))
		elif trigger["Effect"]=="Item":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.ItemTrigger(**trigger))
		elif trigger["Effect"]=="Quest Complete":
			del trigger["Effect"]
			GameEngine.addTrigger(triggers.QuestCompleteTrigger(**trigger))
		else:
			errors.error("Undefined Trigger Effect")

	for obj in GameObjects:

		errors.debug("Adding "+obj["id"])
		#print str(obj["id"])+":"
		#for key in obj.keys():
		#	print key,obj[key]
		#for key in obj["graphicObject"].keys():
		#	print key,obj["graphicObject"][key]
		#for key in obj["graphicObject"]["animations"].keys():
		#	for i in range(0,4):
		#		if obj["graphicObject"]["animations"][key][i] != None:
		#			print key+str(i),len(obj["graphicObject"]["animations"][key][i].getFrames())
		#		else:
		#			print key+str(i),None
		#print "\n"

		for state in obj["mask"].keys():
			if obj["mask"][state] != None:
				img = pygame.image.load(config.AssetPath+str(obj["mask"][state]))
				obj["mask"][state] = maskFromSurface(img)
		if obj["graphicObject"].keys().__contains__("flipX"):
			for state in obj["graphicObject"]["animations"].keys():
				i=0
				if obj["graphicObject"]["animations"][state][1].getNextAnimation() != None:
					nextAnimation = obj["graphicObject"]["animations"][state][1].getNextAnimation()[:-1]+"W"
				else:
					nextAnimation = None
				obj["graphicObject"]["animations"][state][3] = Animation(None,nextAnimation,state+"W")
				for frame in obj["graphicObject"]["animations"][state][1].getFrames():
					i+=1
					obj["graphicObject"]["animations"][state][3].addFrame(AnimationFrame(pygame.transform.flip(frame.image,True,False),frame.delay,None,i-1))
			del obj["graphicObject"]["flipX"]

		#Animation Linker:
		for state in obj["graphicObject"]["animations"].keys():
			for dire in range(0,4):
				if obj["graphicObject"]["animations"][state][dire] == None:
					continue
				nextState = obj["graphicObject"]["animations"][state][dire].getNextAnimation()
				if nextState == None or type(nextState)==Animation:
					continue
				if obj["graphicObject"]["animations"][nextState.rstrip("NESW")][dire].getName()==nextState:
					obj["graphicObject"]["animations"][state][dire].nextAnimation = obj["graphicObject"]["animations"][nextState.rstrip("NESW")][dire]
				else:
					errors.error("Animation linker is officially insufficient. \n(It was already unofficially insufficient, but now things just got worse)\n((Troublemaker: "+state+" -> "+nextState+"))")

		obj["graphicObject"] = GraphicObject(**obj["graphicObject"])
		GraphicEngine.addObject(obj["graphicObject"])
		if obj.keys().__contains__("pushable") and obj["pushable"]==True:
			del obj["pushable"]
			if obj["area"]!=None:
				obj["area"] = pygame.rect.Rect(obj["area"])
			GameEngine.addActor(Pushable(**obj))
		else:
			GameEngine.addActor(GameObject(**obj))

	for npc in NPCs:
		if "AnimeXML" in npc:
			errors.debug("Adding sNPC: "+npc["Id"])
			if npc["Icon"]!=None:
				npc["Icon"]=pygame.image.load(npc["Icon"]).convert()
			npc["Dialog"]=loadDialog(npc["Dialog"])
			#print npc["Dialog"]
			temp = sNPC(**npc)
			GameEngine.addNPC(temp)
			GraphicEngine.addObject(temp.getGraphicObject())
		else:
			errors.debug("Adding NPC: "+npc["Id"])
			if npc["Icon"]!=None:
				npc["Icon"]=pygame.image.load(npc["Icon"]).convert()
			npc["Dialog"]=loadDialog(npc["Dialog"])
			#print npc["Dialog"]
			temp = NPC(**npc)
			GameEngine.addNPC(temp)
			GraphicEngine.addObject(temp.getGraphicObject())

	filer.close()
예제 #24
0
        except IndexError:
            if not self.for_dash_error:
                errors.error(
                    "Error in parsing dashformat.txt; file may have been " +
                    "corrupted. Dashboard may not display data properly or correctly."
                    + " Error message: " +
                    traceback.format_exc(Config.TRACEBACK_LIMIT))
            else:
                errors.debug(
                    "Error in writing data_for_dash again, don't trust dashboard."
                )
            self.for_dash_error = True

        self.data_list = []

if __name__ == '__main__':
    george = DataOutputter()
    for i in range(20):
        errors.debug("===============NEW CYCLE==============")
        george.receive("mux_current", i)
        george.save()
        errors.sendEmail()
        time.sleep(15)
    george.reset()
    for i in range(20):
        errors.debug("===============NEW CYCLE==============")
        george.receive("mux_current", i)
        george.save()
        errors.sendEmail()
        time.sleep(15)