import threading import sys import os import logging import time import socket import struct import zlib import binascii from collections import namedtuple import csv from time import gmtime, strftime import reverse_geocoder as rg from datetime import datetime, timezone import pytz from binascii import unhexlify import struct SOCK_BUFF_SIZE = 100000 global dictionary dictionary = {} helper = {} # This is dictionary to be able to convert OBUID to unitID #TODO: This needs to be updated regularly with open('/var/www/html/certificates.princip.cz/mapa/data/unitinfo.csv', 'r') as file: reader = csv.reader(file) for row in reader: print(row[0]) print(row[1]) helper[int(row[0])] = {'obuid': row[1]} STA = namedtuple('STA', ['time', 'lat', 'lon', 'velocity', 'heading', 'nav', 'nsat', 'alt', 'age', 'active', 'pwr', 'csq']) def expb_expand(x): if x <= 32: return x return ((x & 0x0f) + 0x10) << ((x >> 4) - 1) def convert_STA2(data): data = unhexlify(data) class Struct: pass self = Struct() body = struct.unpack('>ixxxxxxBBBHBBBBBBBBBBBBxxxxxxH', data) self.time = body[0] self.lat = struct.unpack(">i", data[4:8])[0] >> 8 self.lon = struct.unpack(">i", data[7:11])[0] >> 8 self.speed = body[1] self.heading = body[2] self.nav = body[3] / 0x40 self.nsat = body[3] % 0x40 self.alt = body[4] # self.age = expand_expb(body[5]) self.guarding_state = body[6] self.guarding_input = body[7] self.runlevel = body[8] >> 4 self.gsm_state = body[8] & 0x0f self.gsm_state2 = body[9] >> 4 self.csq = body[9] & 0x0f self.reserved0 = body[10] self.adc_uin = body[11] self.adc_an1 = body[12] self.adc_an2 = body[13] self.adc_an3 = body[14] self.adc_an4 = body[15] self.type_of_id = body[16] self.driver = data[27:33] self.fw_ind = body[17] if self.lat == -0x800000: self.lat = None self.lon = None else: self.lat = self.lat * 1.0728837339e-5 self.lon = self.lon * 2.1457672119e-5 if self.heading == 255: self.heading = None else: self.heading *= 2 print(self.lat, self.lon, self.time,self.speed, self.heading, self.nav, self.nsat, self.alt, self.guarding_state, self.guarding_input, self.runlevel, self.gsm_state, self.gsm_state2, self.csq, self.reserved0, self.adc_uin, self.adc_an1, self.adc_an2, self.adc_an3, self.adc_an4, self.type_of_id, self.driver, self.fw_ind) return self.lat, self.lon, self.time, self.speed, self.heading, self.nav, self.nsat, self.alt, self.guarding_state, self.guarding_input, self.runlevel, self.gsm_state, self.gsm_state2, self.csq, self.reserved0, self.adc_uin, self.adc_an1, self.adc_an2, self.adc_an3, self.adc_an4, self.type_of_id, self.driver, self.fw_ind def generateMap(): time.sleep(60) while True: start_time = time.time() with open('/var/www/html/maps.princip.cz/map5/data/testmapdata.csv', 'w') as f: f.write("lat|lng|Name|SN|Unit time|STA received|Lat|Lon|Country|Velocity|Heading|Nav|Nsat|Age|Active|Pwr|Csq|sta\n") print(f"generateMap func initialized") print("Count of units: ", len(dictionary.keys())) # Copy of dict, the original one is modified during the loop dictionary_print = dictionary.copy() for key in dictionary_print.keys(): # Gather all needed data # Get the actual OBUID from helper print(helper[1]['obuid']) if key in helper: obuid = helper[key]['obuid'] print("in helper") else: obuid = "N/A" print("not in helper") msgtype = dictionary[key]['msgtype'] payload = dictionary[key]['payload'] datasta = convert_STA2(payload)#datasta = convert_STA(payload) print("datasta: ", datasta) # Parse unittime if datasta is not None: print(datasta) if datasta[0] is not None and datasta[0] is not "0": timefromsta = int(datasta[0]) tz = pytz.timezone("Europe/Prague") timefromsta = datetime.fromtimestamp(timefromsta, tz) timefromsta = timefromsta.strftime("%Y-%m-%d %H:%M:%S") else: break if datasta[1] is not None: pass else: break lat = datasta[1] lon = datasta[2] velocity = datasta[3] heading = datasta[4] nav = datasta[5] nsat = datasta[6] alt = datasta[7] age = datasta[8] active = datasta[9] pwr = datasta[10] csq = datasta[11] # Real time we got the STA rtime = datetime.now(tz) rtime = rtime.strftime("%Y-%m-%d %H:%M:%S") # Get the state from location coordinates = (lat, lon) if datasta[1] and datasta[2] is not None: results = rg.search(coordinates, mode=1) country = results[0]['cc'] # And finally just feed the file f.write(f"{lat}|{lon}|{obuid}|{msgtype}|{timefromsta}|{rtime}|{lat}|{lon}|{country}|{velocity}|{heading}|{nav}|{nsat}|{alt}|{age}|{active}|{pwr}|{csq}|{payload}\n") # TODO: needs rewrite to trigger this function on request print("--- %s seconds ---" % (time.time() - start_time)) time.sleep(60) def main(): from argparse import ArgumentParser class YArgumentParser(ArgumentParser): def format_help(self): return ArgumentParser.format_help(self) + \ getattr(self, "help_tail", "") parser = YArgumentParser(usage="", epilog="") parser.add_argument("-a", "--ip-addr", type=str, default="192.168.8.11", help="") parser.add_argument("-p", "--ip-port", type=int, default=5001, help="") parser.add_argument("-l", "--log-level", type=int, default=20, help="Logging level") parser.help_tail = """ Example: python script.py -f file ??? """ setup = parser.parse_args() logging.basicConfig(stream=sys.stderr, level=setup.log_level) logging.root.setLevel(setup.log_level) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((setup.ip_addr, setup.ip_port)) thread_generateMap = threading.Thread(name=generateMap,target=generateMap) thread_generateMap.start() while True: print(f"Waiting for data") pack_compress, addr = sock.recvfrom(SOCK_BUFF_SIZE) pack = zlib.decompress(pack_compress) while len(pack) > 0: size, obuid, msg_type = struct.unpack(">HIb", pack[:7]) pack = pack[7:] payload = pack[:size] pack = pack[size:] #print("obuid:{} >{}{}".format(obuid, chr(msg_type), binascii.hexlify(payload))) tz = pytz.timezone("Europe/Prague") rdatetime = datetime.now(tz) rtime = rdatetime.strftime("%Y-%m-%d %H:%M:%S") if obuid not in dictionary: #print(f"Creating dictionary for {obuid}") dictionary[obuid] = {'msgtype': chr(msg_type), 'payload': binascii.hexlify(payload), 'rtime': rtime} else: #print(f"we already have this unit, just update the data") dictionary[obuid]["msgtype"] = chr(msg_type) dictionary[obuid]["payload"] = binascii.hexlify(payload) dictionary[obuid]["rtime"] = rtime #obuid: 2409 > Ab #'62c04b4647352b0ab781071e0400de7c00014b7b00c3ff0000000e3031354c4330722f' if __name__ == '__main__': main()