Python Paho MQTT - байты поступают в обратном порядке по сети через & как правильно повернуть - PullRequest
0 голосов
/ 09 сентября 2018

Существует IoT-устройство, которое отправляет несколько байтов по MQTT / TCP, и я слушаю / подписан на тему под названием StartSession, Master_Topic и т. Д. *

Вот некоторые фактические данные ДО отправки через MQTT:

StartSession | B8-27-EB-42-2C-8B | 1521761472.417744 | 130.20.213.246 | версия 1

Master_Topic | B8-27-EB-42-2C-8B | +1521761474,2269528 | 0,0 | 0,0 | 0,0 | 0,0 | 0,0 | 27,8 | 27,7 | 0,0

Ниже приведен скрипт Python MQTT Paho. Python вызывает функции formatOutputMsg_SIGNAL_A () , formatOutputMsg_Array () и formatOutputMsg () для форматирования данных перед публикацией через MQTT, см. Соответствующий фрагмент (я не могу дать все сценарий, потому что это не мое, а остальное не имеет значения):

Это просто справочная информация, я не могу изменить реализацию Python, это не мой код и не в моем контроле.

Данные StartSession передаются в виде простого текста formatOutputMsg () .

Master_Topic преобразуется в байты перед отправкой с использованием formatOutputMsg_Array () .

Python на IoT:

//relevant section that formats data before publishing over MQTT

# logging.debug("publishing %s %s %s %s", topic, mac, ftime, value)
                    if drop == False:
                        if topic == topics.Master_SIGNAL.name:
                            # convert string array to float array
                            arr = np.array(list(map(float, value)))
                            client.publish(topics.Master_Topic.name, self.formatOutputMsg_Array(mac, arr))
                        elif topic == topics.Raw_SIGNAL.name:
                            ecgTime = float(value[0])
                            ecg = np.array(list(map(float, value[1:])))
                            client.publish(topics.Raw_SIGNAL.name, self.formatOutputMsg_SIGNAL_A(mac, [1, ecg]))
                        else:
                            client.publish(topic, self.formatOutputMsg(mac, value))


//formatting functions used by Master_SIGNAL
 # for the master topic output
    def formatOutputMsg_Array(self, mac, arr):
        mac_bin = mac.encode("ascii");
        mac_len = len(mac_bin);

        arr_bin = array.array('d', arr).tobytes();
        arr_len = len(arr_bin);

        m = struct.pack('qqd%ss%ss' % (mac_len, arr_len), mac_len, arr_len, time.time(), mac_bin, arr_bin);

        return m

    # build output message for SIGNAL_A output.
    def formatOutputMsg_SIGNAL_A(self, mac, arr):
        mac_bin = mac.encode("ascii");
        mac_len = len(mac_bin);

        ecg_time = arr[0];

        ecg_bin = array.array('d', arr[1]).tobytes();
        ecg_len = len(ecg_bin);

        m = struct.pack('qqdd%ss%ss' % (mac_len, ecg_len), mac_len, ecg_len, time.time(), ecg_time, mac_bin, ecg_bin);
        return m

  # build output message.  Formatted like:  "deviceid time value"
    # example:  18:66:DA:43:87:4C,1507228882.122167,98.81615394017435
    def formatOutputMsg(self, mac, value):
        msg = mac + "|" + str(time.time()) + "|" + "|".join(value)
        return msg

Проблема заключается в том, что байты идут в обратном порядке, когда я получаю их на клиенте Android, я не знаю, меняет ли его порядок Python, порядок MSB и LSB, или что-то еще ... в любом случае я написал подпрограмму в своем Android / Java-клиент для переворачивания большинства данных в правильном порядке, , однако я не могу правильно перевернуть / отформатировать поле MAC-АДРЕС.

Соответствующий код Java / Android на стороне клиента:

 //vital tag related topics topic.contains("StartSession") || topic.contains("StopSession") || topic.contains("Alarm") || topic.contains("Raw_ECG")
            else if (topic.contains("Master_Topic") || topic.equalsIgnoreCase("Master_Topic")) {
                Log.i(TAG, "Master_Topic");
                /*Master_Topic entire byte position:mac_len={0->8},arr_len={8->16),time={16->24},mac_bin={24->(24+mac_bin_len)},arr_bin={(24->(24+mac_bin_len)->(24->(24+mac_bin_len)+arr_len_value)}
                 * It seems the bytes are coming in reversed order. There we will use reverse() to reverse bytes. */
                //First, 0->8,length=8,type=long,label=mac_len
                byte[] payload = message.getPayload();
                byte[] mac_len = new byte[8];
                System.arraycopy(payload, 0, mac_len, 0, mac_len.length);
                long mac_len_value = 0;
                //reverse the byte order
                reverse(mac_len);
                //get the mac_len value
                mac_len_value = ByteBuffer.wrap(mac_len).getLong();
                //Second,8->16,length=8,type=long,label=arr_len
                byte[] arr_len = new byte[8];
                System.arraycopy(payload, 8, arr_len, 0, arr_len.length);
                //reverse in place
                reverse(arr_len);
                long arr_len_value = 0;
                arr_len_value = ByteBuffer.wrap(arr_len).getLong();
                //Third,16-24,length=8,type=double,label=time
                byte[] timeBytes = new byte[8];
                System.arraycopy(payload, 16, timeBytes, 0, timeBytes.length);
                reverse(timeBytes);
                double time = ByteBuffer.wrap(timeBytes).getDouble();
                /*Fourth,24->(24+mac_bin.length),type=char,label=mac_bin.
                 * The mac_len_value is of type long, we cannot initialize an array on long length in Java, therefore lets create a List*/
                List < Byte > mac_bin_list = new ArrayList < Byte > ();
                int i = 0;
                while (i < mac_len_value) {
                    mac_bin_list.add((byte) 0);
                    i++;
                }
                //List to array
                Byte[] Mac_Bin = mac_bin_list.toArray(new Byte[mac_bin_list.size()]);
                byte[] mac_bin = Util.toPrimitives(Mac_Bin);
                System.arraycopy(payload, 24, mac_bin, 0, mac_bin.length);
                //ATTENTION - MAC ADDRESS CANNOT BE REVERSED CORRECTLY 
                reverse(mac_bin);
                String mac_address = new String(mac_bin, "US-ASCII");

                //mac_address = Arrays.toString(octets);
                /*Five,(24+mac_bin.length)->(24+mac_bin.length)+(arr_bin.length),type=char,label=arr_bin.
                 * The arr_len_value is of type long, we cannot initialize an array on long length in Java, therefore lets create a List*/
                List < Byte > arr_bin_list = new ArrayList < Byte > ();
                int c = 0;
                while (c < arr_len_value) {
                    arr_bin_list.add((byte) 0);
                    c++;
                }
                Byte[] Arr_Bin = arr_bin_list.toArray(new Byte[arr_bin_list.size()]);
                byte[] arr_bin = Util.toPrimitives(Arr_Bin);
                //Five,24+(mac_bin.length)+(arr_bin.length)->,type=char,label=mac_bin
                System.arraycopy(payload, 24 + (mac_bin.length), arr_bin, 0, arr_bin.length);
                reverse(arr_bin);
                double[] values = toDoubleA(arr_bin);
                /*The bytes section was reversed to give the right order of arrival, but this caused the actual decimal places to be reversed.
                Therefore instead of 2.72 we see 27.2,  therefore if the values is not 0.0 then reverse left & right side of decimal.*/
                // reverse left & right side of decimal
                int d = 0;
                String valueOfData = null;
                for (double data: values) {
                    //if the data is not 0, then we need to reverse the order to get the right value
                    if (data != 0.0) {

                        valueOfData = String.valueOf(data);
                        StringBuilder sb = new StringBuilder(valueOfData);
                        valueOfData = sb.reverse().toString();
                        values[d] = Double.valueOf(valueOfData).doubleValue();

                    }
                    d++;
                }
                StringBuilder datas = new StringBuilder();
                for (double data: values) {
                    datas.append(data + "|");
                }
                datas = datas.reverse();

                Log.i(TAG, "*Master_Topic,mac_len_value=" + mac_len_value + ",arr_len_value=" + arr_len_value + ",time=" + time + ",mac_address=" + mac_address + ",datas=" + datas);


            }
            else
            {
                String msg = new String(message.getPayload(),StandardCharsets.UTF_8);
                Log.e(TAG, "Error topic: " +topic+",not supported!");
            }


        }

        public byte[] toByteArray(int value) {
            return new byte[] {
                    (byte)(value >> 24),
                    (byte)(value >> 16),
                    (byte)(value >> 8),
                    (byte)value};
        }

        int reverseBits(int n)
        {
            int rev = 0;

            // traversing bits of 'n'
            // from the right
            while (n > 0)
            {
                // bitwise left shift
                // 'rev' by 1
                rev <<= 1;

                // if current bit is '1'
                if ((int)(n & 1) == 1)
                    rev ^= 1;

                // bitwise right shift
                //'n' by 1
                n >>= 1;
            }
            // required number
            return rev;
        }


        //from https://www.daniweb.com/programming/software-development/code/216874/primitive-types-as-byte-arrays
        public  long toLong(byte[] data) {
            if (data == null || data.length != 8) return 0x0;
            // ----------
            return (long)(
                    // (Below) convert to longs before shift because digits
                    //         are lost with ints beyond the 32-bit limit
                    (long)(0xff & data[0]) << 56  |
                            (long)(0xff & data[1]) << 48  |
                            (long)(0xff & data[2]) << 40  |
                            (long)(0xff & data[3]) << 32  |
                            (long)(0xff & data[4]) << 24  |
                            (long)(0xff & data[5]) << 16  |
                            (long)(0xff & data[6]) << 8   |
                            (long)(0xff & data[7]) << 0
            );
        }
        //from https://www.daniweb.com/programming/software-development/code/216874/primitive-types-as-byte-arrays
        public  double toDouble(byte[] data) {
            if (data == null || data.length != 8) return 0x0;
            // ---------- simple:
            return Double.longBitsToDouble(toLong(data));
        }
        //from https://www.daniweb.com/programming/software-development/code/216874/primitive-types-as-byte-arrays
        public double[] toDoubleA(byte[] data) {
            if (data == null) return null;
            // ----------
            if (data.length % 8 != 0) return null;
            double[] dbls = new double[data.length / 8];
            for (int i = 0; i < dbls.length; i++) {
                dbls[i] = toDouble( new byte[] {
                        data[(i*8)],
                        data[(i*8)+1],
                        data[(i*8)+2],
                        data[(i*8)+3],
                        data[(i*8)+4],
                        data[(i*8)+5],
                        data[(i*8)+6],
                        data[(i*8)+7],
                } );
            }
            return dbls;
        }

        //reverse the byte array
        public void reverse(byte[] array) {
            if (array == null) {
                return;
            }
            int i = 0;
            int j = array.length - 1;
            byte tmp;
            while (j > i) {
                tmp = array[j];
                array[j] = array[i];
                array[i] = tmp;
                j--;
                i++;
            }
        }

Вот мои журналы Android, когда поступают данные MQTT:

тема: StartSession, полезная нагрузка: 30: 9C: 23: 0F: 55: 34 | 1536460344.7305844 | 130.20.213.246 | версия 1

Master_Topic * Master_Topic, mac_len_value = 17, arr_len_value = 64, время = 1.536460346541999E9, mac_address = * 1 055 * 43: 55: F0: 32: С9: 03 , = Данные | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 27.8 | 27,7 | 0,0

Кажется, что даже в StartSession, когда отправляется простой текст, MAC-АДРЕС изменяется с (правильный) B8-27-EB-42-2C-8B на (неправильный) 30 : 9C: 23: 0F: 55: 34

.

Для MasterTopic я пытался изменить порядок следования байтов, потому что изменение байтов помогло в восстановлении других полей, см. Мой reverse () в коде Java. Однако, я получил (неверный) 43: 55: F0: 32 : C9: 03 вместо правильного (правильного) B8-27-EB-42-2C-8B

Актуальный вопрос) Что происходит с данными MAC-АДРЕСА И как я могу правильно их восстановить ???

Спасибо

Миллион !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...