Пример #1
0
    def in_correct_order(data_format: dict, data: dict):
        """
		Сортирует параметры в нужном порядке.
		На вход получаем словарь, на выход массив

		data_format (dict): словарь с именами параметров и их типом данных
		data (dict): исходные параметры
		"""

        ordered_data = []
        for key, fmt in data_format.items():
            fmt = ''.join(
                [i for i in fmt if not i.isdigit() and not i in 'x?='])
            if fmt in 'hHiIqQnN':
                ordered_data.append(data.get(key, 0))
            elif fmt in 'efd':
                ordered_data.append(data.get(key, 0.0))
            elif fmt in 'cbBsp':
                ordered_data.append(data.get(key, b''))
            elif fmt == '?':
                ordered_data.append(data.get(key, False))
            else:
                error_msg = f"Ошибка в типе данных '{data_format[key]} : {fmt}'"
                logger.critical(error_msg)
                raise ValueError(error_msg)

        return ordered_data
Пример #2
0
    def codec_8(self, packet):
        logger.debug(
            f'[Teltonika] CODEC {self.codec} AVL Data packet:\n{packet}\n')
        packet, timestamp = extract(packet, 8)
        timestamp = b'0x' + timestamp
        timestamp = int(timestamp, 16)
        timestamp /= 1000
        packet, _ = extract_ubyte(packet)  #priority
        packet, lon = extract_int(packet)
        lon /= 10000000
        packet, lat = extract_int(packet)
        lat /= 10000000
        packet, alt = extract_ushort(packet)
        packet, dr = extract_ushort(packet)
        dr = dr // 2
        packet, sat_num = extract_ubyte(packet)
        packet, speed = extract_ushort(packet)

        dt = datetime.datetime.utcfromtimestamp(timestamp)
        data = {
            "datetime": dt,
            "lon": lon,
            "lat": lat,
            "alt": alt,
            "direction": dr,
            "sat_num": sat_num,
            "speed": speed
        }

        logger.debug(f'[Teltonika] AVL Data обработана:\n{data}\n')

        if self.codec == 8:
            packet, EventIO = extract_ubyte(packet)
            packet, NumOfIO = extract_ubyte(packet)

        elif self.codec == 142:
            packet, EventIO = extract_ushort(packet)
            packet, NumOfIO = extract_ushort(packet)

        elif self.codec == 16:
            packet, EventIO = extract_ushort(packet)
            packet, Generation_type = extract_ubyte(packet)
            packet, NumOfIO = extract_ubyte(packet)
        else:
            logger.critical(f"Teltonika неизвестный кодек {self.codec}\n")
            raise ValueError('Unknown codec')

        if EventIO == 385:
            packet, iodata = self.handle_beacon(packet)
        else:
            packet, iodata = self.handle_io(packet)

        data.update({"iodata": iodata})
        logger.debug(f'[Teltonika] AVL IO Data обработана:\n{iodata}\n')

        return packet, data
Пример #3
0
    def get_timestamp(date_time: str):
        """Преобразует дату и время в timestamp
		
		date_time (str): дата и время согласно константе DATE_FORMAT
		"""
        if isinstance(date_time, str):
            return int(mktime(strptime(date_time, DATE_FORMAT)))
        else:
            logger.critical("Неизвестный формат даты и времени")
            raise ValueError("Неизвестный формат времени")
Пример #4
0
def extract_x(packet, letter, length):
    packet, extracted = extract(packet, length)
    extracted = binascii.a2b_hex(extracted)
    try:
        x = struct.unpack(f"!{letter}", extracted)[0]
    except Exception as e:
        logger.critical(
            f'Ошибка в распаковке: len={length} {letter} {extracted}\n{e}')
        raise e

    return packet, x
Пример #5
0
    def get_decoder(self, model):
        if model:
            decoder = load(
                open(self.BASE_PATH + f'avl_ids/{model.lower()}.json', 'r'))
            logger.debug(
                f"[Teltonika] для {self.imei} выбрана модель {model.lower()}\n"
            )
            return decoder

        else:
            logger.critical(
                f"Teltonika для imei {self.imei} модель не найдена\n")
            raise ValueError('Unknown tracker')
Пример #6
0
    def handle_data(self, packet):
        all_data = []
        codec_func = None

        #codec 8
        if self.codec == 8:
            codec_func = self.codec_8

        #codec 8 extended
        elif self.codec == 142:
            codec_func = self.codec_8

        #codec 16
        elif self.codec == 16:
            codec_func = self.codec_16

        else:
            logger.critical(f"Teltonika неизвестный кодек {self.codec}")
            raise ValueError('Unknown codec')

        for rec in range(self.count):
            data = {
                'imei': self.imei,
                'ts': datetime.datetime.utcfromtimestamp(int(time()))
            }

            packet, codecdata = codec_func(packet)
            data.update(codecdata)

            if 'voltage' in data['iodata'].keys():
                if self.ign_v is not None:
                    if data['iodata']['voltage'] > self.ign_v:
                        data['iodata']['ignition'] = 1
                    else:
                        data['iodata']['ignition'] = 0

            all_data.append(data)
            logger.debug(f"[Teltonika] #{len(all_data)}:\n{data}\n")

        logger.debug(f'[Teltonika] data:\n{all_data}\n')
        return all_data
Пример #7
0
    def pack_data(fmt: str, params: list, endiannes=">"):
        """ Запаковщик данных

		fmt (str): формат всего пакета (struct)
		params (list): все параметры пакета
		endiannes (list): byte-order (по умолчанию big-endian)
		"""

        packet = bytes()

        if (('d' in fmt) or ('D' in fmt)) and len(fmt) > 1:
            doubles = []
            f_parts = fmt.split("d")

            for param in params:
                if isinstance(param, float):
                    doubles.append(param)

            for n, part in enumerate(f_parts[:-1]):
                ind = params.index(doubles[n])

                packet += struct.pack(endiannes + part, *params[:ind])
                packet += struct.pack("<d", doubles[n])

                del (params[:ind + 1])

            packet += struct.pack(endiannes + f_parts[-1], *params)

        else:
            try:
                packet += struct.pack(endiannes + fmt, *params)

            except Exception as e:
                logger.critical(
                    f'Ошибка в запаковке данных {fmt} - {params} ({e})')
                raise e

        return packet
Пример #8
0
    def handle_packet(self):
        while not self.stop:
            try:
                packet = binascii.hexlify(self.sock.recv(4096))
            except Exception:
                self.sock.close()
                self.stop = True
                Teltonika.TRACKERS.remove(self)
                logger.debug(
                    f'[Teltonika{self.model}] {self.imei} отключен [{self.addr[0]}:{self.addr[1]}]'
                )
                break

            self.lock.acquire()

            if len(packet) < 8:
                if packet == b'\xff' or packet == b'' or packet == b'ff':
                    continue

                else:
                    logger.error(f'[Teltonika] непонятный пакет: {packet}')
                    self.sock.close()
                    self.stop = True
                    Teltonika.TRACKERS.remove(self)
                    logger.debug(
                        f'[Teltonika{self.model}] {self.imei} отключен [{self.addr[0]}:{self.addr[1]}]'
                    )
                    break

            logger.debug(f'[Teltonika] получен пакет:\n{packet}\n')
            try:
                packet, z = extract_int(packet)  #preamble zero bytes
                assert z == 0, 'Not teltonika packet'
                packet, data_len = extract_uint(packet)
                packet, self.codec = extract_ubyte(packet)
                packet, self.count = extract_ubyte(packet)
                logger.debug(
                    f'[Teltonika] codec={self.codec} rec_count={self.count}\n')

            except Exception as e:
                with open('tracker_receiver/src/logs/errors.log', 'a') as fd:
                    fd.write(f'Ошибка в распаковке {packet}\n{e}\n')

            if self.codec in (8, 142, 16):
                self.data = self.handle_data(packet)
                self.data = prepare_geo(self.data)
                count = insert_geo(self.data)
                logger.info(
                    f'Teltonika{self.model} {self.imei} принято {count}/{len(self.data)} записей'
                )
                self.sock.send(struct.pack("!I", count))

            elif self.codec in (12, 13, 14):
                result = self.handle_command(packet)
                resp = {"action": "response", "result": result}
                resp = dumps(resp)
                self.command_response = resp
                logger.debug(
                    f'[Teltonika] ответ на команду принят\n{result}\n')

            else:
                logger.critical(f"Teltonika неизвестный кодек {self.codec}")
                raise ValueError('Unknown codec')

            self.lock.release()
            sleep(2)

        del (self)
Пример #9
0
    def handle_io(self, packet):
        data = {}

        for extract_func in [
                extract_byte, extract_short, extract_int, extract_longlong
        ]:
            if self.codec == 8 or self.codec == 16:
                packet, count = extract_ubyte(packet)
            elif self.codec == 142:
                packet, count = extract_ushort(packet)
            else:
                logger.critical(f"Teltonika неизвестный кодек {self.codec}\n")
                raise ValueError('Unknown codec')

            iodata = {}
            for _ in range(count):
                if self.codec == 8:
                    packet, io_id = extract_ubyte(packet)

                elif self.codec == 142 or self.codec == 16:
                    packet, io_id = extract_ushort(packet)

                else:
                    logger.critical(
                        f"Teltonika неизвестный кодек {self.codec}\n")
                    raise ValueError('Unknown codec')

                packet, io_val = extract_func(packet)

                if str(io_id) not in self.decoder.keys():
                    logger.error(
                        f'[Teltonika] Неизвестный AVL IO ID {io_id}\n')

                else:
                    if str(io_id) in self.assign.keys():
                        ikey = self.assign[str(io_id)]
                        if '*' in ikey:
                            spl = ikey.split('*')
                            ikey, k = spl[0], spl[1]
                            io_val = round(io_val * float(k), 4)

                        iodata.update({ikey: io_val})

                    elif self.decoder[str(io_id)] in self.assign.keys():
                        ikey = self.assign[self.decoder[str(io_id)]]
                        if '*' in ikey:
                            spl = ikey.split('*')
                            ikey, k = spl[0], spl[1]
                            io_val = round(io_val * float(k), 4)

                        iodata.update({ikey: io_val})

                    else:
                        iodata.update({self.decoder[str(io_id)]: io_val})

            data.update(iodata)

        if self.codec == 142:
            packet, count = extract_ushort(packet)

            iodata = {}
            for _ in range(count):
                packet, io_id = extract_ushort(packet)
                packet, length = extract_ushort(packet)

                if length > 8:
                    packet, io_val = extract(packet, length)
                else:
                    packet, io_val = extract_x(packet, 'q', length)

                if str(io_id) not in self.decoder.keys():
                    logger.error(
                        f'[Teltonika] Неизвестный AVL IO ID {io_id}\n')

                else:
                    if str(io_id) in self.assign.keys():
                        ikey = self.assign[str(io_id)]
                        if '*' in ikey:
                            spl = ikey.split('*')
                            ikey, k = spl[0], spl[1]
                            io_val = round(io_val * float(k), 4)

                        iodata.update({ikey: io_val})

                    elif self.decoder[str(io_id)] in self.assign.keys():
                        ikey = self.assign[self.decoder[str(io_id)]]
                        if '*' in ikey:
                            spl = ikey.split('*')
                            ikey, k = spl[0], spl[1]
                            io_val = round(io_val * float(k), 4)

                        iodata.update({ikey: io_val})

                    else:
                        iodata.update({self.decoder[str(io_id)]: io_val})

            data.update(iodata)

        return packet, data
Пример #10
0
    def paste_data_into_params(self, p, data, formats=None):
        """
		Знак "&" в значении параметра json означает ссылку на переменную
		после этого знака следует написать имя параметра, который вы передали в класс
		и этот параметр возьмет значение этой переменной

		Также здесь есть срезы, делаются они точно так же, как и в питоне, но нет шагов.

		Например: "param": "&myvar[3:7]"
		
		Args:
			p (dict): параметры, в которых необходимо заменить специальные выражения переменными
			data (dict): словарь, из которого берутся переменные для параметров
			formats (dict): форматы struct для параметров (p)
			
		Returns:
			dict: параметры со вставленными значениями

		"""
        def find_format(name):
            """Глобальный поиск формата в протоколе
			name (str): имя параметра
			"""
            for key, item in self.protocol["FORMATS"].items():
                if name in item.keys():
                    return item[name]

        params = deepcopy(p)  #глубокая копия чтобы избежать недоразумений
        for n in params.keys():
            if isinstance(params[n], str):
                slc = ('[' in params[n])
                if "&" == params[n][0]:
                    other_format = False
                    params[n] = params[n][1:]

                    if slc:
                        params[n], slc = params[n].split("[")
                        slc = slc[:-1]

                        if formats:
                            if find_format(n) != find_format(params[n]):
                                other_format = True  #формат исходной переменной несовпадает с требуемым форматом

                    if params[n] in data.keys():
                        params[n] = data[params[n]]

                    else:
                        error_msg = f"Параметр '{params[n]}' не найден"
                        logger.critical(error_msg)
                        raise KeyError(error_msg)

                    if slc:
                        l_slc, r_slc = slc.split(':')
                        if ((len(l_slc) > 0) & (len(r_slc) > 0)):
                            params[n] = params[n][int(l_slc):int(r_slc)]
                        elif ((len(l_slc) > 0) & (not len(r_slc) > 0)):
                            params[n] = params[n][int(l_slc):]
                        elif ((not len(l_slc)) > 0 & (len(r_slc) > 0)):
                            params[n] = params[n][:int(r_slc)]
                        else:
                            error_msg = f"Неправильно указан срез параметра {params[n]}[{l_slc}:{r_slc}]"
                            logger.critical(error_msg)
                            raise KeyError(error_msg)

                    if formats:
                        if other_format:
                            fmt = formats[n]
                            #согласно обозначениям типов struct
                            if fmt in 'hHiIqQnN':
                                params[n] = int(params[n])
                            elif fmt in 'efd':
                                params[n] = float(params[n])
                            elif fmt in 'cbBsp':
                                params[n] = bytes(
                                    str(params[n]).encode('ascii'))
                            else:
                                error_msg = f"Ошибка в типе данных '{params[n]} : {fmt}'"
                                logger.critical(error_msg)
                                raise ValueError(error_msg)

            else:
                continue

        return params