Как создать простой LoRa мессенджер: обмен текстовыми сообщениями между устройствами без интернета

a7d16aee5a52da4c2d4084b6967732c3.jpg
[
    {
        "id": "2f52923ccb63864b",
        "type": "tab",
        "label": "LoRa P2P Messaging",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "bb3960f039b0d5d9",
        "type": "group",
        "z": "2f52923ccb63864b",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "9362510d02f2a3cd",
            "653c14cbd7d04855",
            "411dc5558acb5d69",
            "7c928c5461e79357",
            "3d751b388616d680",
            "d7f18a1a41328fc2",
            "39310643b351cbe9",
            "0ad15eca9748f8c2",
            "2aa5a90b9a47e61a",
            "41c7e933bc23bf15",
            "e226f98ef20c6e3c",
            "f193efb9e856e239",
            "8215f7a39798258c",
            "9f6693be1c896628",
            "796a0c4c7349efdc",
            "d2b59a73f776232a",
            "c9a150394bb8dd8b",
            "229f643b2e4dc980"
        ],
        "x": 34,
        "y": 79,
        "w": 1892,
        "h": 342
    },
    {
        "id": "0c3ab2711ef23cd5",
        "type": "group",
        "z": "2f52923ccb63864b",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "3fcbc4e3b39e37e0",
            "550ac146763bb1cf",
            "ded89b84d1895114",
            "29ee0d0fd91ab5d4",
            "e03995b19d8f6ff1",
            "3a8125696d200c02",
            "31d9cb982c9d1c95",
            "30d506a8ea905666",
            "9f9472d611ecf562"
        ],
        "x": 34,
        "y": 479,
        "w": 1032,
        "h": 202
    },
    {
        "id": "9362510d02f2a3cd",
        "type": "debug",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "3: Кодированные данные",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 940,
        "y": 180,
        "wires": []
    },
    {
        "id": "653c14cbd7d04855",
        "type": "debug",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "1: Сырые данные",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 390,
        "y": 120,
        "wires": []
    },
    {
        "id": "3fcbc4e3b39e37e0",
        "type": "function",
        "z": "2f52923ccb63864b",
        "g": "0c3ab2711ef23cd5",
        "name": "Декодирование данных",
        "func": "// Установите значения для соответствия символов и их кодировок\nconst encodingTable = {\n    ' ': '00',\n    '.': '01',\n    ',': '02',\n    '!': '03',\n    '?': '04',\n    '-': '05',\n    '(': '06',\n    ')': '07',\n    'а': '08',\n    'б': '09',\n    'в': '0A',\n    'г': '0B',\n    'д': '0C',\n    'е': '0D',\n    'ж': '0E',\n    'з': '0F',\n    'и': '10',\n    'й': '11',\n    'к': '12',\n    'л': '13',\n    'м': '14',\n    'н': '15',\n    'о': '16',\n    'п': '17',\n    'р': '18',\n    'с': '19',\n    'т': '1A',\n    'у': '1B',\n    'ф': '1C',\n    'х': '1D',\n    'ц': '1E',\n    'ч': '1F',\n    'ш': '20',\n    'щ': '21',\n    'ъ': '22',\n    'ы': '23',\n    'ь': '24',\n    'э': '25',\n    'ю': '26',\n    'я': '27',\n    'А': '28',\n    'Б': '29',\n    'В': '2A',\n    'Г': '2B',\n    'Д': '2C',\n    'Е': '2D',\n    'Ё': '2E',\n    'Ж': '2F',\n    'З': '30',\n    'И': '31',\n    'Й': '32',\n    'К': '33',\n    'Л': '34',\n    'М': '35',\n    'Н': '36',\n    'О': '37',\n    'П': '38',\n    'Р': '39',\n    'С': '3A',\n    'Т': '3B',\n    'У': '3C',\n    'Ф': '3D',\n    'Х': '3E',\n    'Ц': '3F',\n    'Ч': '40',\n    'Ш': '41',\n    'Щ': '42',\n    'Ъ': '43',\n    'Ы': '44',\n    'Ь': '45',\n    'Э': '46',\n    'Ю': '47',\n    'Я': '48',\n    ', а': '49',\n    ', б': '4A',\n    ', в': '4B',\n    ', г': '4C',\n    ', д': '4D',\n    ', е': '4E',\n    ', ж': '4F',\n    ', з': '50',\n    ', и': '51',\n    ', й': '52',\n    ', к': '53',\n    ', л': '54',\n    ', м': '55',\n    ', н': '56',\n    ', о': '57',\n    ', п': '58',\n    ', р': '59',\n    ', с': '5A',\n    ', т': '5B',\n    ', у': '5C',\n    ', ф': '5D',\n    ', х': '5E',\n    ', ц': '5F',\n    ', ч': '60',\n    ', ш': '61',\n    ', щ': '62',\n    ', ъ': '63',\n    ', ы': '64',\n    ', ь': '65',\n    ', э': '66',\n    ', ю': '67',\n    ', я': '68',\n    ' а ': '69',\n    ' в ': '6A',\n    ' и ': '6B',\n    ' к ': '6C',\n    ' с ': '6D',\n    ' у ': '6E',\n    ' я ': '6F',\n    'будет': '70',\n    'буду': '71',\n    'бы': '72',\n    'был': '73',\n    'была': '74',\n    'были': '75',\n    'вас': '76',\n    'вот': '77',\n    'все': '78',\n    'всех': '79',\n    'вы': '7A',\n    'где': '7B',\n    'для': '7C',\n    'его': '7D',\n    'ее': '7E',\n    'ей': '7F',\n    'ем': '80',\n    'ему': '81',\n    'если': '82',\n    'есть': '83',\n    'ею': '84',\n    'зачем': '85',\n    'здесь': '86',\n    'из': '87',\n    'или': '88',\n    'их': '89',\n    'как': '8A',\n    'какая': '8B',\n    'какие': '8C',\n    'какое': '8D',\n    'какой': '8E',\n    'когда': '8F',\n    'которая': '90',\n    'которое': '91',\n    'которые': '92',\n    'который': '93',\n    'кто': '94',\n    'меня': '95',\n    'мне': '96',\n    'мог': '97',\n    'могла': '98',\n    'могли': '99',\n    'могу': '9A',\n    'могут': '9B',\n    'мое': '9C',\n    'моего': '9D',\n    'моей': '9E',\n    'может': '9F',\n    'можете': 'A0',\n    'мои': 'A1',\n    'моим': 'A2',\n    'моих': 'A3',\n    'мой': 'A4',\n    'моя': 'A5',\n    'мы': 'A6',\n    'на': 'A7',\n    'наш': 'A8',\n    'наша': 'A9',\n    'наше': 'AA',\n    'наши': 'AB',\n    'не': 'AC',\n    'него': 'AD',\n    'нему': 'AE',\n    'ним': 'AF',\n    'но': 'B0',\n    'он': 'B1',\n    'они': 'B2',\n    'от': 'B3',\n    'отсюда': 'B4',\n    'оттуда': 'B5',\n    'по': 'B6',\n    'потом': 'B7',\n    'почему': 'B8',\n    'свое': 'B9',\n    'свои': 'BA',\n    'свой': 'BB',\n    'своя': 'BC',\n    'сейчас': 'BD',\n    'сказал': 'BE',\n    'сказала': 'BF',\n    'сколько': 'C0',\n    'сюда': 'C1',\n    'такая': 'C2',\n    'также': 'C3',\n    'такие': 'C4',\n    'такое': 'C5',\n    'такой': 'C6',\n    'там': 'C7',\n    'твое': 'C8',\n    'твоего': 'C9',\n    'твоей': 'CA',\n    'твоем': 'CB',\n    'твои': 'CC',\n    'твоих': 'CD',\n    'твой': 'CE',\n    'твоя': 'CF',\n    'тебя': 'D0',\n    'теперь': 'D1',\n    'то': 'D2',\n    'тогда': 'D3',\n    'туда': 'D4',\n    'тут': 'D5',\n    'ты': 'D6',\n    'что': 'D7',\n    'этим': 'D8',\n    'это': 'D9',\n    'этого': 'DA',\n    'этой': 'DB',\n    'этому': 'DC',\n    'этот': 'DD',\n    'хм': 'DE',\n    '1': 'DF',\n    '2': 'E0',\n    '3': 'E1',\n    '4': 'E2',\n    '5': 'E3',\n    '6': 'E4',\n    '7': 'E5',\n    '8': 'E6',\n    '9': 'E7',\n    '0': 'E8',\n    'Привет': 'E9',\n    'Привет,': 'EA',\n    'Хабр': 'EB'\n};\n\n// Обратное преобразование\nfunction decodeString(encodedString) {\n    let decodedString = '';\n\n    for (let i = 0; i < encodedString.length; i += 2) {\n        const code = encodedString.substr(i, 2);\n\n        // Поиск символа в таблице\n        const char = Object.keys(encodingTable).find(key => encodingTable[key] === code);\n\n        // Если символ найден, добавляем его к раскодированной строке\n        if (char) {\n            decodedString += char;\n        } else {\n            // Если символ не найден, оставляем его без изменений\n            decodedString += code;\n        }\n    }\n\n    // Создаем объект сообщения и возвращаем результат\n    const msg = { payload: decodedString };\n    return msg;\n}\n\n// Закодированная строка для обратного преобразования\nconst encodedString = msg.payload;\n\n// Применяем функцию к закодированной строке\nconst resultDecoding = decodeString(encodedString);\n\n// Выводим результат в debug\nreturn resultDecoding;\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 590,
        "y": 580,
        "wires": [
            [
                "550ac146763bb1cf",
                "ded89b84d1895114",
                "31d9cb982c9d1c95"
            ]
        ]
    },
    {
        "id": "550ac146763bb1cf",
        "type": "debug",
        "z": "2f52923ccb63864b",
        "g": "0c3ab2711ef23cd5",
        "name": "6: Декодированные данные",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 880,
        "y": 520,
        "wires": []
    },
    {
        "id": "411dc5558acb5d69",
        "type": "function",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "Кодирование данных",
        "func": "// Протокол обмена\nconst encodingTable = {\n    ' ': '00',\n    '.': '01',\n    ',': '02',\n    '!': '03',\n    '?': '04',\n    '-': '05',\n    '(': '06',\n    ')': '07',\n    'а': '08',\n    'б': '09',\n    'в': '0A',\n    'г': '0B',\n    'д': '0C',\n    'е': '0D',\n    'ж': '0E',\n    'з': '0F',\n    'и': '10',\n    'й': '11',\n    'к': '12',\n    'л': '13',\n    'м': '14',\n    'н': '15',\n    'о': '16',\n    'п': '17',\n    'р': '18',\n    'с': '19',\n    'т': '1A',\n    'у': '1B',\n    'ф': '1C',\n    'х': '1D',\n    'ц': '1E',\n    'ч': '1F',\n    'ш': '20',\n    'щ': '21',\n    'ъ': '22',\n    'ы': '23',\n    'ь': '24',\n    'э': '25',\n    'ю': '26',\n    'я': '27',\n    'А': '28',\n    'Б': '29',\n    'В': '2A',\n    'Г': '2B',\n    'Д': '2C',\n    'Е': '2D',\n    'Ё': '2E',\n    'Ж': '2F',\n    'З': '30',\n    'И': '31',\n    'Й': '32',\n    'К': '33',\n    'Л': '34',\n    'М': '35',\n    'Н': '36',\n    'О': '37',\n    'П': '38',\n    'Р': '39',\n    'С': '3A',\n    'Т': '3B',\n    'У': '3C',\n    'Ф': '3D',\n    'Х': '3E',\n    'Ц': '3F',\n    'Ч': '40',\n    'Ш': '41',\n    'Щ': '42',\n    'Ъ': '43',\n    'Ы': '44',\n    'Ь': '45',\n    'Э': '46',\n    'Ю': '47',\n    'Я': '48',\n    ', а': '49',\n    ', б': '4A',\n    ', в': '4B',\n    ', г': '4C',\n    ', д': '4D',\n    ', е': '4E',\n    ', ж': '4F',\n    ', з': '50',\n    ', и': '51',\n    ', й': '52',\n    ', к': '53',\n    ', л': '54',\n    ', м': '55',\n    ', н': '56',\n    ', о': '57',\n    ', п': '58',\n    ', р': '59',\n    ', с': '5A',\n    ', т': '5B',\n    ', у': '5C',\n    ', ф': '5D',\n    ', х': '5E',\n    ', ц': '5F',\n    ', ч': '60',\n    ', ш': '61',\n    ', щ': '62',\n    ', ъ': '63',\n    ', ы': '64',\n    ', ь': '65',\n    ', э': '66',\n    ', ю': '67',\n    ', я': '68',\n    ' а ': '69',\n    ' в ': '6A',\n    ' и ': '6B',\n    ' к ': '6C',\n    ' с ': '6D',\n    ' у ': '6E',\n    ' я ': '6F',\n    'будет': '70',\n    'буду': '71',\n    'бы': '72',\n    'был': '73',\n    'была': '74',\n    'были': '75',\n    'вас': '76',\n    'вот': '77',\n    'все': '78',\n    'всех': '79',\n    'вы': '7A',\n    'где': '7B',\n    'для': '7C',\n    'его': '7D',\n    'ее': '7E',\n    'ей': '7F',\n    'ем': '80',\n    'ему': '81',\n    'если': '82',\n    'есть': '83',\n    'ею': '84',\n    'зачем': '85',\n    'здесь': '86',\n    'из': '87',\n    'или': '88',\n    'их': '89',\n    'как': '8A',\n    'какая': '8B',\n    'какие': '8C',\n    'какое': '8D',\n    'какой': '8E',\n    'когда': '8F',\n    'которая': '90',\n    'которое': '91',\n    'которые': '92',\n    'который': '93',\n    'кто': '94',\n    'меня': '95',\n    'мне': '96',\n    'мог': '97',\n    'могла': '98',\n    'могли': '99',\n    'могу': '9A',\n    'могут': '9B',\n    'мое': '9C',\n    'моего': '9D',\n    'моей': '9E',\n    'может': '9F',\n    'можете': 'A0',\n    'мои': 'A1',\n    'моим': 'A2',\n    'моих': 'A3',\n    'мой': 'A4',\n    'моя': 'A5',\n    'мы': 'A6',\n    'на': 'A7',\n    'наш': 'A8',\n    'наша': 'A9',\n    'наше': 'AA',\n    'наши': 'AB',\n    'не': 'AC',\n    'него': 'AD',\n    'нему': 'AE',\n    'ним': 'AF',\n    'но': 'B0',\n    'он': 'B1',\n    'они': 'B2',\n    'от': 'B3',\n    'отсюда': 'B4',\n    'оттуда': 'B5',\n    'по': 'B6',\n    'потом': 'B7',\n    'почему': 'B8',\n    'свое': 'B9',\n    'свои': 'BA',\n    'свой': 'BB',\n    'своя': 'BC',\n    'сейчас': 'BD',\n    'сказал': 'BE',\n    'сказала': 'BF',\n    'сколько': 'C0',\n    'сюда': 'C1',\n    'такая': 'C2',\n    'также': 'C3',\n    'такие': 'C4',\n    'такое': 'C5',\n    'такой': 'C6',\n    'там': 'C7',\n    'твое': 'C8',\n    'твоего': 'C9',\n    'твоей': 'CA',\n    'твоем': 'CB',\n    'твои': 'CC',\n    'твоих': 'CD',\n    'твой': 'CE',\n    'твоя': 'CF',\n    'тебя': 'D0',\n    'теперь': 'D1',\n    'то': 'D2',\n    'тогда': 'D3',\n    'туда': 'D4',\n    'тут': 'D5',\n    'ты': 'D6',\n    'что': 'D7',\n    'этим': 'D8',\n    'это': 'D9',\n    'этого': 'DA',\n    'этой': 'DB',\n    'этому': 'DC',\n    'этот': 'DD',\n    'хм': 'DE',\n    '1': 'DF',\n    '2': 'E0',\n    '3': 'E1',\n    '4': 'E2',\n    '5': 'E3',\n    '6': 'E4',\n    '7': 'E5',\n    '8': 'E6',\n    '9': 'E7',\n    '0': 'E8',\n    'Привет': 'E9',\n    'Привет,': 'EA',\n    'Хабр': 'EB'\n};\n\n// Функция преобразования строки в кодировку\nfunction encodeString(inputString) {\n    const maxBytes = 51;\n    let encodedStrings = [];\n\n    // Если строка больше 51 байта, разбиваем на посылки\n    if (Buffer.from(inputString, 'utf-8').length > maxBytes) {\n        let currentChunk = '';\n        let currentChunkBytes = 0;\n\n        for (let i = 0; i < inputString.length; i++) {\n            const char = inputString[i];\n            const charBytes = Buffer.from(char, 'utf-8').length;\n\n            // Проверяем, можно ли добавить символ к текущей посылке\n            if (currentChunkBytes + charBytes <= maxBytes) {\n                currentChunk += char;\n                currentChunkBytes += charBytes;\n            } else {\n                // Если символ не помещается, добавляем текущую посылку в результат\n                encodedStrings.push(encodeChunk(currentChunk));\n\n                // Начинаем новую посылку\n                currentChunk = char;\n                currentChunkBytes = charBytes;\n            }\n        }\n\n        // Добавляем последнюю посылку в результат\n        if (currentChunk !== '') {\n            encodedStrings.push(encodeChunk(currentChunk));\n        }\n    } else {\n        // Строка помещается в одну посылку\n        encodedStrings.push(encodeChunk(inputString));\n    }\n\n    // Возвращаем генератор, чтобы поочередно возвращать строки с задержкой\n    let index = 0;\n    const sendNext = () => {\n        if (index < encodedStrings.length) {\n            const value = encodedStrings[index++];\n            setTimeout(() => {\n                node.send({ payload: value });\n                sendNext();\n            }, 2000); // Задержка в 2 секунд\n        }\n    };\n\n    sendNext();\n}\n\n// Вспомогательная функция для кодирования части строки\nfunction encodeChunk(chunk) {\n    let encodedChunk = '';\n\n    // Разбиваем часть строки на слова\n    const words = chunk.split(' ');\n\n    // Кодируем каждое слово отдельно\n    for (let i = 0; i < words.length; i++) {\n        const word = words[i];\n\n        // Проверяем, является ли слово словом в словаре\n        if (encodingTable.hasOwnProperty(word)) {\n            encodedChunk += encodingTable[word];\n        } else {\n            // Кодируем каждый символ слова отдельно\n            for (let j = 0; j < word.length; j++) {\n                const char = word[j];\n\n                // Проверяем, есть ли символ в таблице\n                if (encodingTable.hasOwnProperty(char)) {\n                    encodedChunk += encodingTable[char];\n                } else {\n                    // Если символ отсутствует в таблице, оставляем его без изменений\n                    encodedChunk += char;\n                }\n            }\n        }\n\n        // Добавляем пробел между словами\n        if (i < words.length - 1) {\n            encodedChunk += encodingTable[' '];\n        }\n    }\n\n    return encodedChunk;\n}\n\n// Применяем функцию к входной строке\nconst inputString = msg.payload;\nencodeString(inputString);",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 680,
        "y": 240,
        "wires": [
            [
                "3d751b388616d680",
                "d7f18a1a41328fc2",
                "9362510d02f2a3cd"
            ]
        ]
    },
    {
        "id": "7c928c5461e79357",
        "type": "ui_text_input",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "label": "Данные для отправки",
        "tooltip": "",
        "group": "afb27fbd0a803a11",
        "order": 1,
        "width": 0,
        "height": 0,
        "passthru": true,
        "mode": "text",
        "delay": "1000",
        "topic": "topic",
        "sendOnBlur": true,
        "className": "",
        "topicType": "msg",
        "x": 160,
        "y": 240,
        "wires": [
            [
                "653c14cbd7d04855",
                "e226f98ef20c6e3c",
                "8215f7a39798258c"
            ]
        ]
    },
    {
        "id": "ded89b84d1895114",
        "type": "ui_text",
        "z": "2f52923ccb63864b",
        "g": "0c3ab2711ef23cd5",
        "group": "afb27fbd0a803a11",
        "order": 3,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Получено сообщение:",
        "format": "{{msg.payload}}",
        "layout": "row-left",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 870,
        "y": 580,
        "wires": []
    },
    {
        "id": "3d751b388616d680",
        "type": "ui_text",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "group": "afb27fbd0a803a11",
        "order": 2,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Кодированное сообщение:",
        "format": "{{msg.payload}}",
        "layout": "row-left",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 940,
        "y": 300,
        "wires": []
    },
    {
        "id": "d7f18a1a41328fc2",
        "type": "function",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "Формирование AT команды",
        "func": "// Получаем входные данные из сообщения msg.payload\nvar inputString = msg.payload;\n\n// Формируем строку в требуемом формате\nvar outputString = 'AT+PSEND=' + inputString;\n\n// Создаем новый объект сообщения и устанавливаем в него преобразованную строку\nmsg.payload = outputString;\n\n// Возвращаем объект сообщения\nreturn msg;\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 940,
        "y": 240,
        "wires": [
            [
                "39310643b351cbe9",
                "0ad15eca9748f8c2",
                "9f6693be1c896628"
            ]
        ]
    },
    {
        "id": "39310643b351cbe9",
        "type": "serial out",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "serial": "baa0d15198c00a18",
        "x": 1820,
        "y": 240,
        "wires": []
    },
    {
        "id": "29ee0d0fd91ab5d4",
        "type": "serial in",
        "z": "2f52923ccb63864b",
        "g": "0c3ab2711ef23cd5",
        "name": "",
        "serial": "baa0d15198c00a18",
        "x": 130,
        "y": 580,
        "wires": [
            [
                "e03995b19d8f6ff1"
            ]
        ]
    },
    {
        "id": "0ad15eca9748f8c2",
        "type": "debug",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "4: Отправка данных на UART",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1250,
        "y": 180,
        "wires": []
    },
    {
        "id": "e03995b19d8f6ff1",
        "type": "function",
        "z": "2f52923ccb63864b",
        "g": "0c3ab2711ef23cd5",
        "name": "Фильтруем Payload",
        "func": "// Получаем входные данные из сообщения msg.payload\nvar inputString = msg.payload;\n\n// Разбиваем строку по символу \":\" и выбираем последний элемент массива\nvar parts = inputString.split(':');\nvar extractedValue = parts[parts.length - 1];\n\n// Создаем новый объект сообщения и устанавливаем в него извлеченное значение\nmsg.payload = extractedValue;\n\n// Возвращаем объект сообщения\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 580,
        "wires": [
            [
                "3fcbc4e3b39e37e0"
            ]
        ]
    },
    {
        "id": "2aa5a90b9a47e61a",
        "type": "ui_button",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "group": "afb27fbd0a803a11",
        "order": 4,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Режим P2P",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "AT+NWM=0",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 1590,
        "y": 380,
        "wires": [
            [
                "39310643b351cbe9"
            ]
        ]
    },
    {
        "id": "41c7e933bc23bf15",
        "type": "ui_button",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "group": "afb27fbd0a803a11",
        "order": 7,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Режим LoRaWAN",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "AT+NWM=1",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 1570,
        "y": 340,
        "wires": [
            [
                "39310643b351cbe9"
            ]
        ]
    },
    {
        "id": "e226f98ef20c6e3c",
        "type": "ui_button",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "group": "afb27fbd0a803a11",
        "order": 5,
        "width": 0,
        "height": 0,
        "passthru": true,
        "label": "Передача сообщений ВКЛ",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "AT+PRECV=0",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 420,
        "y": 180,
        "wires": [
            [
                "d2b59a73f776232a",
                "229f643b2e4dc980"
            ]
        ]
    },
    {
        "id": "f193efb9e856e239",
        "type": "ui_button",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "group": "afb27fbd0a803a11",
        "order": 6,
        "width": 0,
        "height": 0,
        "passthru": true,
        "label": "Прием сообщений ВКЛ",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "AT+PRECV=65534",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 1550,
        "y": 300,
        "wires": [
            [
                "39310643b351cbe9"
            ]
        ]
    },
    {
        "id": "8215f7a39798258c",
        "type": "delay",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "",
        "pauseType": "delay",
        "timeout": "250",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 390,
        "y": 240,
        "wires": [
            [
                "411dc5558acb5d69"
            ]
        ]
    },
    {
        "id": "9f6693be1c896628",
        "type": "function",
        "z": "2f52923ccb63864b",
        "g": "bb3960f039b0d5d9",
        "name": "Задержка на Прием ВКЛ",
        "func": "// Получаем контекст текущего узла\nvar context = flow.get('sessionContext') || {};\n\n// Инициализируем массив для хранения сообщений текущей сессии\ncontext.sessionMessages = context.sessionMessages || [];\n\n// Добавляем новые сообщения в массив\ncontext.sessionMessages = context.sessionMessages.concat(msg.payload);\n\n// Устанавливаем таймер на 4 секунд для завершения сессии\nif (context.sessionTimer) {\n    clearTimeout(context.sessionTimer);\n}\n\ncontext.sessionTimer = setTimeout(function () {\n    // Когда таймер срабатывает, находим последнее сообщение\n    var lastMessage = context.sessionMessages[context.sessionMessages.length - 1];\n\n    // Очищаем контекст для следующей сессии\n    context.sessionMessages = [];\n    context.sessionTimer = null;\n\n    // Возвращаем последнее сообщение\n    node.send({ payload: lastMessage });\n}, 2500); // 2 секунд таймер\n\n// Если есть еще время до конца сессии, сохраняем контекст\nflow.set('sessionContext', context);\n\n// Возвращаем null или что-то еще, чтобы показать, что обработка не завершена\nreturn null;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1240,
        "y": 300,
        "wires": [
            [
                "f193efb9e856e239",
                "796a0c4c7349efdc"
            ]
        ]
    },
    {
        "id": "3a8125696d200c02",
        "type": "ui_template",
        "z": "2f52923ccb63864b",
        "g": "0c3ab2711ef23cd5",
        "group": "afb27fbd0a803a11",
        "name": "History",
        "order": 9,
        "width": "10",
        "height": "5",
        "format": "
", "storeOutMessages": true, "fwdInMessages": true, "resendOnRefresh": true, "templateScope": "local", "className": "", "x": 980, "y": 640, "wires": [ [] ] }, { "id": "31d9cb982c9d1c95", "type": "function", "z": "2f52923ccb63864b", "g": "0c3ab2711ef23cd5", "name": "History", "func": "// Проверяем, если кнопка \"clearHistory\" была нажата\nif (msg.payload === ' ') {\n // Очищаем историю\n context.history = [];\n}\n\n// Добавление нового сообщения в историю\ncontext.history = context.history || [];\ncontext.history.push(msg.payload);\n\n// Ограничение длины истории (если нужно)\nvar maxLength = 25; // Максимальная длина истории\nif (context.history.length > maxLength) {\n context.history.shift(); // Удаляем самое старое сообщение\n}\n\n// Отправка истории на вход ui_template\nreturn { payload: context.history.join('
') };", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 820, "y": 640, "wires": [ [ "3a8125696d200c02" ] ] }, { "id": "30d506a8ea905666", "type": "ui_button", "z": "2f52923ccb63864b", "g": "0c3ab2711ef23cd5", "name": "", "group": "afb27fbd0a803a11", "order": 8, "width": 0, "height": 0, "passthru": false, "label": "СlearHistory", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": " ", "payloadType": "str", "topic": "topic", "topicType": "msg", "x": 630, "y": 640, "wires": [ [ "31d9cb982c9d1c95" ] ] }, { "id": "796a0c4c7349efdc", "type": "debug", "z": "2f52923ccb63864b", "g": "bb3960f039b0d5d9", "name": "5: Переключене Прием ВКЛ", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 1570, "y": 180, "wires": [] }, { "id": "d2b59a73f776232a", "type": "debug", "z": "2f52923ccb63864b", "g": "bb3960f039b0d5d9", "name": "2: Переключене Передача ВКЛ", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 720, "y": 120, "wires": [] }, { "id": "c9a150394bb8dd8b", "type": "comment", "z": "2f52923ccb63864b", "g": "bb3960f039b0d5d9", "name": "Отправка данных", "info": "", "x": 150, "y": 120, "wires": [] }, { "id": "9f9472d611ecf562", "type": "comment", "z": "2f52923ccb63864b", "g": "0c3ab2711ef23cd5", "name": "Прием данных", "info": "", "x": 140, "y": 520, "wires": [] }, { "id": "229f643b2e4dc980", "type": "serial out", "z": "2f52923ccb63864b", "g": "bb3960f039b0d5d9", "name": "", "serial": "baa0d15198c00a18", "x": 660, "y": 180, "wires": [] }, { "id": "afb27fbd0a803a11", "type": "ui_group", "name": "Участник 1", "tab": "af8825e119b68714", "order": 1, "disp": true, "width": "11", "collapse": false, "className": "" }, { "id": "baa0d15198c00a18", "type": "serial-port", "name": "", "serialport": "/dev/ttyUSB3", "serialbaud": "115200", "databits": "8", "parity": "none", "stopbits": "1", "waitfor": "", "dtr": "none", "rts": "none", "cts": "none", "dsr": "none", "newline": "500", "bin": "false", "out": "interbyte", "addchar": "\\r\\n", "responsetimeout": "2000" }, { "id": "af8825e119b68714", "type": "ui_tab", "name": "Обмен сообщениями 1", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false } ]

© Habrahabr.ru