Ejemplo n.º 1
0
    def handle(self, *args, **options):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((TCP_IP, TCP_PORT))
        #s.connect((TCP_IP, TCP_PORT))
        #sending the auth message, receiving the response and sending an ack message
        key = authentication(s)
        CPRSession.objects.all().delete()
        cprkey = CPRSession(key=key,time=datetime.now())
        cprkey.save()
        #mounting the XML response to server
        seckey_msg = "<?xml version=\"1.0\" encoding=\"ASCII\"?><Package><Header Version=\"1.0\" Id=\"2\" /><Data SessionId=\""+key+"\" /></Package>"
        close_msg =  "<?xml version=\"1.0\" encoding=\"ASCII\"?>\n<Package>\n  <Header Version=\"1.0\" Id=\"99\" />\n  <Data SessionId=\""+key+"\" />\n</Package>"
        self.stdout.write('>> Starting main loop.\n')
        #sending the response to the server, and awaiting the outbox message
        s.send(ack_msg)
        s.send(seckey_msg)
        data = s.recv(BUFFER_SIZE)
        s.send(ack_msg)
        #listening all information given by CPR.

# >> ==================================================== +-------------------------------+-\
# >> ==================================================== | MAIN EXTRACTOR LOOP           |  >
# >> ==================================================== +-------------------------------+-/

        self.stdout.write('>> Starting main loop.\n')
        while 1:
        
            # if there is messages to read in the socket
            if ([s],[],[]) == select.select([s],[],[],0):
            
                # reads and inform the acknowledgement of the message
                inbox = s.recv(BUFFER_SIZE)
                s.send(ack_msg)
                try:

# >> ==================================================== +-------------------------------+-\
# >> ==================================================== | PARSING XML                   |  >
# >> ==================================================== +-------------------------------+-/
                
                  # parse the received xml and turns it into a dict
                  self.stdout.write("================================\n"+inbox+"\n================================\n")
                  xml =  ElementTree.fromstring(inbox.strip(""))
                  xmldict = XmlDictConfig(xml)
                  # checks if it's a tracking table
                  if xmldict['Header']['Id'] == '198':
                      try:
# >> ==================================================== +-------------------------------+-\
# >> ==================================================== | DATABASE LOOKUP               |  >
# >> ==================================================== +-------------------------------+-/
                          
                          # tries to pick the equipment and the date of the tracking table
                          e = Equipment.objects.get(serial=xmldict['TCA']['SerialNumber'])
                          v = Vehicle.objects.get(equipment=e)
                          sys = lowestDepth(e.system.all())
                          searchdate = datetime.strptime(xmldict['Event']['EventDateTime'], "%Y/%m/%d %H:%M:%S")
                          try:
                              # tries to pick the tracking table with the same equipment and eventdate
                              t = Tracking.objects.get(Q(equipment=e) & Q(eventdate=searchdate))
                    
                          except ObjectDoesNotExist:
                              # probably the try statement above will raise this exception, so the script shall create the tracking
                              t = Tracking(equipment=e, eventdate=searchdate, msgtype=xmldict['Datagram']['MsgType'])
                              t.save()
                              
# >> ==================================================== +-------------------------------+-\
# >> ==================================================== | CUSTOMFIELD AND DATA MERGING  |  >
# >> ==================================================== +-------------------------------+-/                              

                              #iterates over the input dicts and saves the information for each matching custom field in the database table
                              for k_type,d_type in xmldict.items():
                                  if type(d_type).__name__ == 'dict':
                                      for k_tag,d_tag in d_type.items():
                                          try:
                                              #find the customfield to put the tracking data under, then create and save it
                                              # TODO: if needed, optimize this database lookup doing one big search out of the for statement
                                              # TODO: and iterate over the list
                                              c = CustomField.objects.get(Q(type=k_type)&Q(tag=k_tag))
                                              tdata = TrackingData(tracking=t,type=c,value=d_tag)
                                              tdata.save()
                                          except ObjectDoesNotExist:
                                              pass
                                              
# >> ================================================= +----------------------------------+-\
# >> ================================================= | GEOCODING AND MORE DATA ADDITION |  >
# >> ================================================= +----------------------------------+-/

                              #reverse geocoding in the background
                              geocodeinfo = ReverseGeocode(str(xmldict['GPS']['Lat']),str(xmldict['GPS']['Long']))
                              
                              #get the custom fields for the right things
                              geocodefields = CustomField.objects.filter(type='Geocode')
                              geodict = {}
                              for field in geocodefields:
                                geodict[field.tag] = field
                              
                              #saving the tracking datas to the tracking
                              TrackingData(tracking=t, type=geodict['Address'],value=geocodeinfo[1]).save()
                              TrackingData(tracking=t, type=geodict['City'],value=geocodeinfo[2]).save()
                              TrackingData(tracking=t, type=geodict['State'],value=geocodeinfo[3]).save()
                              TrackingData(tracking=t, type=geodict['PostalCode'],value=geocodeinfo[4]).save()
                              
                              #saving the vehicle tracking data
                              field = CustomField.objects.get(tag="Vehicle")
                              TrackingData(tracking=t,type=field,value=v.id).save()
                              
                              #saving the system tracking data
                              field = CustomField.objects.get(tag="System")
                              TrackingData(tracking=t,type=field,value=sys.id).save()
                              
                              # print the success message            
                              self.stdout.write('>> The tracking table sent on '+str(searchdate)+' for the equipment '+ xmldict['TCA']['SerialNumber'] +' has been saved successfully.\n')

# >> ==================================================== +-------------------------------+-\
# >> ==================================================== | ALERTS AND DATA COMPARISON    |  >
# >> ==================================================== +-------------------------------+-/
                        
      # Here is the main alert handler. First, queries the database looking if there's some alert that matches the 
      # received tracking. After that, for each alert in the result of the query, alert in each way available.
                        
                          #queries the vehicle in the database
                          vehicle = v #(has been done before)
                          
                          #if the last alert sent for the vehicle is not null
                          if vehicle.last_alert_date is not None:
                              #calculate the difference between the last alert and a possibly new one                        
                              total_seconds = (searchdate - vehicle.last_alert_date).days * 24 * 60 * 60 + (searchdate - vehicle.last_alert_date).seconds
                              #check if there's enough time between the last alert sent and a possibly new one
                              if total_seconds > vehicle.threshold_time*60:
                                  self.stdout.write('>> Alert threshold reached.\n')
                                  vehicle.last_alert_date = searchdate
                                  vehicle.save()
                                  #pick the alert records to check                                  
                                  alerts = Alert.objects.filter(Q(vehicle=vehicle) & Q(time_end__gte=searchdate) & Q(time_start__lte=searchdate) & Q(active=True))                              
                                  
                                  #iterates over the inputs and checks if it is needed to send the alert
                                  for k_type,d_type in dict(xmldict['Input'].items() + xmldict['LinearInput'].items()).items():
                                      
                                      try:
                                          
                                          #dont look for GPS information now (will be done for the geofences)
                                          c = CustomField.objects.get(Q(tag=k_type)& ~Q(type='GPS'))
                                          
                                          #function that returns true if the alert shall be sent, and false if not.
                                          for alert in alerts:
                                              
                                              if AlertComparison(self,alert,c,d_type):         
                                                  #function that sends in the proper ways the alerts
                                                  AlertSender(self,alert,vehicle,searchdate,geocodeinfo)
                                              else:
                                                  pass
                                                  # self.stdout.write('>> Nao entrou no Alert Comparison.\n')
                                                                     
                                      except ObjectDoesNotExist:
                                          # self.stdout.write('>> Entrou no except "objectdoesnotexist".\n')
                                          #exception thrown for the inputs and linear inputs that didn't match
                                          #any field in the database
                                          pass
                                          
# >> ==================================================== +-------------------------------+-\
# >> ==================================================== | GEOFENCE COMPARISONS          |  >
# >> ==================================================== +-------------------------------+-/

                                  #check if the position is inside (or outside) some geofence alert
                                  geoalerts = alerts.filter(trigger__custom_field__tag='GeoFence')

                                  for alert in geoalerts:
                                    if GeofenceComparison(self,alert,xmldict["GPS"]["Lat"], xmldict["GPS"]["Long"]):
                                        AlertSender(self,alert,vehicle,searchdate)
                          else: #if the vehicle never had thrown alerts, give him a last alert date
                              vehicle.last_alert_date = searchdate
                              vehicle.save()
                
                      #exceptions thrown if the equipment does not exist.
                      # TODO: create the equipments that isn't in the equipments database table
                      except ObjectDoesNotExist:
                          pass
                      except KeyError:
                          pass
                          
                  #if the message is a command status message
                  elif xmldict['Header']['Id'] == '106':
                  # TODO: update the status for the given command
                    print xmldict
                    e = Vehicle.objects.get(equipment__serial=xmldict['Data']['Serial'])
                    c = ItrackCommand.objects.filter(equipment=e)
                    c = c.get(state=u'0')
                    self.stdout.write(str(c)+","+xmldict['Data']['Status']+ "\n")
                    if xmldict['Data']['Status'] == '3': #message was sent to the GPRS network
                        #as we only have one command per time in the command table, change the command status
                        self.stdout.write('here!\n')
                        c.state = u"1"
                        c.time_received = datetime.strptime(xmldict['Header']['TimeStamp'], "%Y/%m/%d %H:%M:%S")                        
                        c.save()
                                    
                                     
                #except ParseError:       
                #TODO : parse the things when two tracking tables comes to the inbox - this case is kind of rare,
                #TODO : but makes the extractor crash when the 'except ParseError' is turned on.
                except:
                  pass
Ejemplo n.º 2
0
    def run(self):
      # Have our thread serve "forever":
      
      #System and Vehicle custom fields
      
      systemField = CustomField.objects.get(tag="System")
      vehicleField = CustomField.objects.get(tag="Vehicle")
      root_system = System.objects.get(parent=None)
      while True:
       try:
         if ((self.stopped() and clientPool.qsize() == 0) or
            (self.stopped() and threading.active_count() > 2)):
            self.setStatus("Thread stopped.")
            break
            
         
         # Get a client out of the queue
         try:
            client = clientPool.get(True,1)
         except Queue.Empty:
            client = None
         # Check if we actually have an actual client in the client variable:
         if client != None:
         
            status_display[0]+=1
            
            
            inbox =  client[0].recv(8192)
            self.setStatus('Processing data from '+client[1][0])
            client[0].close()
    #            file = codecs.open("./")
            datadict = json.loads(inbox)
            if datadict['Type'] == 'MTC State Tracking':
                serial_data = datadict['serial']
                sendstate_data = datadict['sendstate']
                date_data = datadict['date']
                e = Equipment.objects.get(Q(serial=serial_data))
                searchdate = datetime.strptime( date_data, "%Y-%m-%d %H:%M:%S")
                t = Tracking(equipment=e, eventdate=searchdate,  msgtype="TRACKING")
                t.save()
                e.lasttrack_update = t.pk
                e.save()
                TrackingData(tracking=t,type=CustomField.objects.get(id=67), value=sendstate_data).save()
                
            elif datadict['Type'] == 'Tracking':
            # tries to pick the equipment and the date of the tracking table
                try:
                    #first, check if the equipment exists
                    type_id = datadict['Identification']['EquipType']
                    e = Equipment.objects.get(
                        Q(serial=datadict['Identification']['Serial'])
                    )

                    try:
                        #print(e.name)
                        #second, if the vehicle exists, for that equipment, 
                        # insert the tracking head on the tracking table
                        vehicle = Vehicle.objects.get(equipment=e)
                        sys = lowestDepth(e.system.all())
                        
                        try:
                            searchdate = datetime.strptime( 
                                datadict['Identification']['Date'],
                                "%Y/%m/%d %H:%M:%S")
                            
                        except ValueError:
                            searchdate = datetime.strptime( 
                                datadict['Identification']['Date'],
                                "%Y-%m-%d %H:%M:%S")
                        
                        self.setStatus('Tracking at: '+str(searchdate)+' from equip: '+ str(e))
                                
                        #create the tracking
                        t = Tracking(
                            equipment=e, 
                            eventdate=searchdate, 
                            msgtype="TRACKING")
                        t.save()
                        e.lasttrack_data = t.pk
                        e.save()
                        
                        # mounting the list of data received
                        io = {}
                        try:
                            if datadict.has_key("Input") and datadict['Input'] != None:
                                io['Input'] = datadict['Input'].copy()
                        except Exception as err:
                            print(inbox)
                            print("#2",err)
                            pass
                        try:
                            io['LinearInput'] = datadict['LinearInput'].copy()
                        except Exception as err:
                            print(inbox)
                            print("#3",err)
                            pass
                        has_output = False
                        try:
                            if datadict.has_key("Output") and datadict['Output'] != None:
                                io['Output'] = datadict['Output'].copy()
                                has_output = True
                        except Exception as err:
                            print(inbox)
                            print("#4",err)
                            pass
                        try:
                            io['GPS'] = datadict['GPS'].copy()
                        except Exception as err:
                            print(inbox)
                            print("#5",err)
                            pass
                        
                        try:
                            if has_output :
                                for x0 in xrange(1,8):
                                    ttype = 53 + x0
                                    TrackingData(tracking=t,type=CustomField.objects.get(id=ttype), value=io['Output']['Output' + str(x0)]).save()
                        except Exception as err:
                            print(inbox)
                            print("#6",err)
                            pass

                        #filtering that list, leaving only the registered
                        #custom fields for the equipment type
                        io_filtered = {}
                        for cf in equipTypeDict[int(type_id)]:
                            for k,v in io.items():
                                if not io_filtered.has_key(k):
                                    #pre-populating to avoid KeyError
                                    #io_filtered[k] = {}
                                    pass
                                if (cf.tag in v.keys() and
                                              cf.type == k):
                                    #mounting the dict, associating the custom
                                    #field with the value in the tracking
                                    io_filtered[cf] = v[cf.tag]                                            
                            
                        #inserting the tracking datas under the tracking head
                        
                        for k_cf,v in io_filtered.items():                                
                            TrackingData(
                                    tracking=t,
                                    type=k_cf,
                                    value=v
                            ).save()

                        
                        cflist = [x[0] for x in io_filtered.items()]
                        
                        for cf in equipTypeDict[int(type_id)]:
                            if cf not in cflist:
                                TrackingData( tracking=t, type=cf, value="OFF" ).save()
                        try:
                            #reverse geocoding in the background
                            _lat = float(datadict['GPS']['Lat'])
                            _lon = float(datadict['GPS']['Long'])
                            geocodeinfo = ReverseGeocode(_lat,_lon)
                            status_display[1] += 1
                            #saving the acquired geocode information
                            TrackingData( tracking=t, type=geoDict['Address'], value=geocodeinfo[1]).save()
                            TrackingData( tracking=t, type=geoDict['City'], value=geocodeinfo[2] ).save()
                            TrackingData( tracking=t, type=geoDict['State'], value=geocodeinfo[3] ).save()
                            TrackingData( tracking=t, type=geoDict['PostalCode'], value=geocodeinfo[4] ).save()
                            self.setStatus('Reverse geocode finished. ')
                            # and adding extra vehicle and system custom fields
                            TrackingData( tracking=t, type=vehicleField, value=vehicle.id).save()
                            TrackingData( tracking=t, type=systemField,value=sys.id).save()
                            #queries the vehicle in the database
                            #if the last alert sent for the vehicle is not null
                        except Exception as err:
                         #   for th in threading.enumerate():
                         #       if isinstance(th,OutputThread):
                         #           th.stop()
                            print(inbox)
                            print("#7",err)
                            pass
                        if vehicle.last_alert_date is not None:
                          total_seconds = (
                                (searchdate - vehicle.last_alert_date).days *
                                24 * 60 * 60 + 
                                (searchdate - vehicle.last_alert_date).seconds
                                )
                                
                          # check if there's enough time between the last alert 
                          # sent and a possibly new one
                          if total_seconds > vehicle.threshold_time*60:
                            vehicle.last_alert_date = searchdate
                            vehicle.save()
                            #pick the alert records to check                                  
                            alerts = Alert.objects.filter(
                                Q(vehicle=vehicle) & 
                                Q(time_end__gte=searchdate) & 
                                Q(time_start__lte=searchdate) & 
                                Q(active=True)
                                )                              
                            geoalerts = alerts.filter(
                                trigger__custom_field__tag='GeoFence'
                           "Waiting to process data." )
                            # iterates over the inputs and checks if it 
                            # is needed to send the alert
                            for k,v in io_filtered.items():
                                if k.type in ['Input','LinearInput']:
                                    for alert in alerts:
                                        if AlertComparison(self,alert,k,v):
                                            self.setStatus('Found alert to send.')
                                            AlertSender(self,alert,vehicle,
                                                        searchdate,geocodeinfo)
                            
                            #checking the geofence alerts
                            for alert in geoalerts:
                                if GeofenceComparison( self,alert,
                                            io["GPS"]["Lat"], 
                                            io["GPS"]["Long"]
                                            ):
                                    self.setStatus('Found geofence alert to send.')
                                    AlertSender(self,alert,vehicle,searchdate)
                            
                          else: 
                              # if the vehicle never had thrown alerts, 
                              # give him a last alert date
                              vehicle.last_alert_date = searchdate
                              vehicle.save()
                              
                        self.setStatus("Waiting to process data.")
                                    
                    except ObjectDoesNotExist:
                        self.setStatus("Equipment without vehicle. Dropping received data.")
                        pass
                except ObjectDoesNotExist:
                    self.setStatus('Equipment not found on the database.'+
                        'Creating and inserting under the root system')
                    
                    try:
                        eq = Equipment(
                            name = datadict['Identification']['Serial'],
                            serial = datadict['Identification']['Serial'],
                            type = equipTypeIndex[type_id],
                            available = True
                        )
                    
                        eq.save()
                        eq.system.add(root_system)
                    except IntegrityError:
                        pass
                    except KeyError:
                        self.setStatus('Equip Type "'+str(type_id) + '" not '+
                    'recognized. Dropping recived data.')
                except KeyError:
                    self.setStatus('Equip Type "'+str(type_id) + '" not '+
                    'recognized. Dropping recived data.')
                          
            elif datadict['Type'] == 'Command':
                pass
            elif datadict['Type'] == 'CarMeter':
                try:
                    serial_data = datadict['Identification']['Serial']

                    e = Equipment.objects.get(Q(serial=serial_data))
                    try:
                        searchdate = datetime.strptime( datadict['Identification']['Date'],"%Y/%m/%d %H:%M:%S")
                    except ValueError:
                        searchdate = datetime.strptime( datadict['Identification']['Date'],"%Y-%m-%d %H:%M:%S")
                    t = Tracking(equipment=e, eventdate=searchdate,  msgtype="CARMETER")
                    t.save()
                    e.lastdriver = t.pk
                    e.save()
                    #datadict['Identification']['CardId']
                    TrackingData(tracking=t,type=CustomField.objects.get(id=68), value=datadict['Identification']['CardId']).save()
                except Exception as err:
                    print(err.args)
               
            client[0].close()
            
         else:
            self.setStatus("Waiting to process data.")
       except Exception as err:
         print("#1",err)
         pass