__author__ = 'asc' import os import datetime from urllib import request, parse import requests import json from cell_connection import initializeUartPort, baseOperations, initializeLogs import logging from requests_toolbelt import MultipartEncoder import csv import base64 SCRIPTDIR = os.path.dirname(os.path.abspath(__file__)) logger = logging.getLogger(__name__) def add_keys_if_necessary(existing_file, test_dict): all=None try: with open(existing_file,'r') as f: reader = csv.reader(f) header = [] try: header = next(reader) except StopIteration as e: pass if len(header) == 0: header = list(test_dict.keys()) writer = csv.DictWriter(existing_file, test_dict.keys(), extrasaction='ignore') writer.writeheader() # if not header >= list(test_dict.keys()) or not header <= list(test_dict.keys()): if len(set (header)-set(test_dict.keys()))>0: existing_keys =set (header) data_keys = set (test_dict.keys()) keys_to_add = data_keys - existing_keys all = [] for key in keys_to_add: header.append(key) all.append(header) for row in reader: all.append(row) pass except (OSError, IOError, TypeError) as e: header = list(test_dict.keys()) f=open(existing_file, 'a+') writer = csv.DictWriter(f, test_dict.keys(), extrasaction='ignore') writer.writeheader() f.close() if all is not None: with open (existing_file, 'w') as f: writer = csv.writer(f) writer.writerows(all) return header class Datalogger(): def __init__(self, missiontime, text_path, log_path, photo_path): self._mt = missiontime self.text_path=text_path self.log_path=os.path.join(log_path, 'MISSION {}.csv'.format(self._mt.name)) self.photo_path=photo_path pass def log(self, r): self._record = r._get_dict() # logger.info('Recording {}'.format(self._record)) for k in self._record.keys(): if k is 'b': if self._record[k] is not list: l = [self._record[k]] else: l = self._record[k] for item in l: logger.debug("item: {}".format(self._record), extra={'MISSION_TIME': self._mt.now(), 'MISSION_ID':self._mt.name}) item['at']=self._mt.to_absolutetime(item['mt']) item['mid']=self._mt.name header = add_keys_if_necessary(self.log_path, item) keys = header log=open(self.log_path, 'a') writer = csv.DictWriter(log, keys, extrasaction='ignore') writer.writerow(item) log.close() logger.info('Barometer data recorded',extra={'MISSION_TIME': self._mt.now(), 'MISSION_ID':self._mt.name}) elif k is 'i': if self._record[k] is tuple: l = [self._record[k]] else: l = self._record[k] for item in l: # Form is ('name', file object, 'type') filename = item[0] file = base64.b64decode(bytes(item[1],'ascii')) folder = os.path.join(self.photo_path, self._mt.mid) file_path = os.path.join(self.photo_path, folder, filename) if not os.path.exists(folder): os.makedirs(folder) with open(file_path, 'wb') as f: f.write(file) # file.save(os.path.join(self.photo_path, filename)) logger.info('Image data recorded',extra={'MISSION_TIME': self._mt.now(), 'MISSION_ID':self._mt.name}) return 'success' class Datareporter(): from lib.sim900.inetgsm import SimInetGSM def __init__(self, missiontime, url, data_path, image_path, ping_path, server_port, com_port_name=None, baud_rate=None, use_lan = False, path=SCRIPTDIR): #TODO communication self.mt = missiontime self.url = url self.server_port=server_port self.image_path = image_path self.data_path = data_path self.com_port_name = com_port_name self.baud_rate = baud_rate self.ping_path = ping_path self.use_lan = use_lan self._transpondence=None if not use_lan: self.port = initializeUartPort(portName=self.com_port_name, baudrate=self.baud_rate) d = baseOperations(self.port, logger) if not d is None: (self.gsm, self.imei) = d self.inet = self.SimInetGSM(self.port, logger) logger.info('ip = {0}'.format(self.inet.ip), extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) logger.debug('attaching GPRS', extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) if not self.inet.attachGPRS('wholesale', '', '', 1): logger.error('error attaching GPRS', extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) return False #register mission number to server intiate = Record(str(self.mt.timezero),'zt') # intiate.add(self.mt.mid,'mid') self.send(intiate, _intiating_report=True) @property def status (self): #TODO status check try: return (0, 'Data reporter functioning properly') except Exception as e: return (1, 'Data reporter error: %s' % e) def _send_data(self, message, _intiating_report=False): response=None m = MultipartEncoder(fields=message) if _intiating_report: path = '{0}'.format(self.image_path) else: path = '{0}/{1}'.format(self.image_path,self.mt.mid) if self.use_lan: logger.info ('Sending transpondence using LAN', extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) response = requests.post('{0}:{1}/{2}'.format(self.url, self.server_port, path), data=m.read(), headers={'Content-Type': m.content_type}) pass elif not self.use_lan: logger.info ('Sending transpondence using modem', extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) # logger.debug('attaching GPRS') # if not self.inet.attachGPRS('wholesale', '', '', 1): # logger.error('error attaching GPRS') # return False logger.debug('ip = {0}'.format(self.inet.ip), extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) logger.debug('making HTTP POST request', extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) if not self.inet.httpPOST( self.url, self.server_port, "/{}".format(path), m.to_string(), contentType=m.content_type ): logger.error('error making HTTP POST: {0}'.format(self.inet.errorText), extra={'MISSION_TIME': self.mt.now(), 'MISSION_ID':self.mt.name}) return False if self.inet.httpResponse is not None: response = str(self.inet.httpResponse).replace('\n\r', '\n') else: response = 'empty response' if _intiating_report: if type (response) is str: mid = response else: mid = response.text self.mt.set_mid(mid) return response def send(self, t, _intiating_report=False): self._transpondence = t._get_dict() self._transpondence['mt'] = self.mt.now() # print ('Send transpondence {}'.format(self._transpondence)) for k in self._transpondence.keys(): # if self._transpondence[k] is list or self._transpondence[k] is dict or self._transpondence[k] is float: if type(self._transpondence) is dict: self._transpondence[k] = json.dumps(self._transpondence[k]) r = self._send_data(message=self._transpondence, _intiating_report=_intiating_report) #On error, do not clear transpondence if not r: self._transpondence = self._transpondence return None class Record(): def __init__(self,first_item=None, first_item_type=None): # if self._transpondence is None: self._transpondence={} if first_item and first_item_type: self.add(first_item, first_item_type) def add(self, data, info_type='data'): if type(data) is not list: if self._transpondence.get(info_type) is not None: if type(self._transpondence.get(info_type)) is list: self._transpondence[info_type].append(data) else: self._transpondence[info_type] = [self._transpondence[info_type]] self._transpondence[info_type].append(data) else: self._transpondence[info_type]=data else: if self._transpondence.get(info_type) is not None: if type(self._transpondence.get(info_type)) is list: self._transpondence[info_type] + data else: self._transpondence[info_type] = [self._transpondence[info_type]] self._transpondence[info_type] + data else: self._transpondence[info_type]=data def _get_dict(self): return self._transpondence