Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Off Topic
  4. Meshtastic

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.7k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.2k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    16
    1
    3.1k

Meshtastic

Geplant Angeheftet Gesperrt Verschoben Off Topic
4 Beiträge 3 Kommentatoren 1.1k Aufrufe 3 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • M Offline
    M Offline
    mark77
    schrieb am zuletzt editiert von Homoran
    #1

    Moin,

    seit ein paar Tagen experimentiere ich mit meshtastic (meshtastic.org).

    Im Forum wollte ich mal schauen ob es gleichgesinnte gibt, die das System erfolgreich in ioBroker eingebunden haben und wenn ja, wie?

    Gruß,
    Mark

    T J 2 Antworten Letzte Antwort
    0
    • M mark77

      Moin,

      seit ein paar Tagen experimentiere ich mit meshtastic (meshtastic.org).

      Im Forum wollte ich mal schauen ob es gleichgesinnte gibt, die das System erfolgreich in ioBroker eingebunden haben und wenn ja, wie?

      Gruß,
      Mark

      T Offline
      T Offline
      ToGe88
      Developer
      schrieb am zuletzt editiert von
      #2

      @mark77 Moin, zwar schon ein bisschen älter der Beitrag aber ich antworte mal. Ich teste gerade auch ein wenig mit Meshtastic herum und habe mir ein Script erstellt welches über die Python Meshtastic CLI die Daten in den ioBroker holt. (Könnte man ggfs. auch zu einem Adapter umbauen zu einem späteren Zeitpunkt).

      Das Script erzeugt Datenpunkte um die Telemetrie Daten der Nodes zu überwachen, dafür werden diese alle 30 Sekunden vom Modul ausgelesen. Zudem ist es möglich Nachrichten an Chats, Direktnachrichten an Nodes, Traceroutes und Pings zu versenden. Der Empfang von Nachrichten ist aktuell nicht möglich. Ist alles noch mehr eine Bastellösung und im Testbetrieb. Die Integration ist aber schon sehr hilfreich wenn man zum Reichweitentest aus der Ferne z.B. Nachrichten von der "Basis" auslösen will oder prüfen möchte ob der mobile Node empfangen wird obwohl man dort kein ACK erhält. Möglich wäre auch eine Begrüßung von neuen Nodes auf dem Default Channel wenn sie in Reichweite der Basis mit ioBroker kommen ;)

      Wichtig ist das die Meshtastic CLI (https://meshtastic.org/docs/software/python/cli/installation/) für den User installiert wird unter welchem auch der ioBroker läuft. Ich nutze aktuell die Verbindung per WLAN, wenn es über die USB Schnittstelle laufen soll müsste man an den entsprechenden stellen die Befehle für exec anpassen.

      var deviceIp = '192.168.1.117';
      
      var chats = [
          { name: 'Default', id: 0 },
          { name: 'Benutzerkanal 1', id: 1 },
          { name: 'Benutzerkanal 2', id: 2 }
      ];
      
      
      function updateNodes() {
          exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --nodes', async function (error, result, stderr) {
              if (result.includes('Connected to radio')) {
                  var nodes = parseData(result);
                  handleNodes(nodes);
              }
          });
      }
      
      function handleNodes(nodes) {
          nodes.forEach(node => {
              node.ID = node.ID.replace("!", "");
              if (nodeIsKnown(node.ID)) {
                  updateNode(node);
              } else {
                  createNode(node);
                  setTimeout(function() {
                      updateNode(node);
                  },4000);
              }
          });
      }
      
      function updateNode(data) {
      var nodeInfoStates = [
              {id: 'id', name: 'NodeID', type: 'string', unit: null, log: false},
              {id: 'user', name: 'User', type: 'string', unit: null, log: false},
              {id: 'alias', name: 'Alias', type: 'string', unit: null, log: false},
              {id: 'location', name: 'Location', type: 'string', unit: null, log: true},
              {id: 'altitude', name: 'Altitude', type: 'number', unit: 'm', log: true},
              {id: 'chanUtil', name: 'Channel util.', type: 'number', unit: '%', log: true},
              {id: 'txAir', name: 'Tx air util.', type: 'number', unit: '%', log: true},
              {id: 'snr', name: 'SNR', type: 'number', unit: 'db', log: true},
              {id: 'channel', name: 'Channel', type: 'string', unit: null, log: false},
              {id: 'lastHeard', name: 'Last heard', type: 'string', unit: null, log: true},
              {id: 'battery', name: 'Battery', type: 'number', unit: '%', log: true}
          ];
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.id', data.N, true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.user', data.User, true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.alias', data.AKA, true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.location', data.Latitude.replace('°', '') + ', ' + data.Longitude.replace('°', ''), true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.altitude', parseFloat(data.Altitude.replace(' m', '')), true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.chanUtil', parseFloat(data['Channel util.'].replace('%', '')), true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.txAir', parseFloat(data['Tx air util.'].replace('%', '')), true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.snr', parseFloat(data.SNR.replace(' dB', '')), true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.channel', data.Channel, true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.lastHeard', data.LastHeard, true);
          setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.battery', parseFloat(data.Battery.replace('%', '')), true);
      }
      
      function createNode(data) {
          log('creating new node', 'info');
          var newNode = {
              "type": 'channel',
              "common": {
                  "name": data.User,
              }
          };
          setObject('0_userdata.0.Meshtastic.Nodes.' + data.ID, newNode);
          createNodeStates(data.ID);
      }
      
      function createNodeStates(id) {
      
          var infoChannel = {
              "type": 'channel',
              "common": {
                  "name": 'Info',
              }
          };
          setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.info', infoChannel);
      
          var nodeInfoStates = [
              {id: 'id', name: 'NodeID', type: 'string', unit: null, log: false},
              {id: 'user', name: 'User', type: 'string', unit: null, log: false},
              {id: 'alias', name: 'Alias', type: 'string', unit: null, log: false},
              {id: 'location', name: 'Location', type: 'string', unit: null, log: true},
              {id: 'altitude', name: 'Altitude', type: 'number', unit: 'm', log: true},
              {id: 'chanUtil', name: 'Channel util.', type: 'number', unit: '%', log: true},
              {id: 'txAir', name: 'Tx air util.', type: 'number', unit: '%', log: true},
              {id: 'snr', name: 'SNR', type: 'number', unit: 'db', log: true},
              {id: 'channel', name: 'Channel', type: 'string', unit: null, log: false},
              {id: 'lastHeard', name: 'Last heard', type: 'string', unit: null, log: true},
              {id: 'battery', name: 'Battery', type: 'number', unit: '%', log: true}
          ];
      
          nodeInfoStates.forEach(state => {
              var currentObject = {
                  "type": 'state',
                  "common": {
                      "name": state.name,
                      "type": state.type,
                      "unit": state.unit,
                      "read": true,
                      "write": false,
                  }
              };
              setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.info.' + state.id, currentObject);
          });
      
      
          var commandChannel = {
              "type": 'channel',
              "common": {
                  "name": 'Command',
              }
          };
          setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.command', commandChannel);
      
          var nodeCommandStates = [
              {id: 'sendMessage', name: 'Direktnachricht an Node senden', type: 'string', role: 'value'},
              {id: 'sendPing', name: 'Ping an Node senden', type: 'boolean', role: 'button'},
              {id: 'sendTraceRoute', name: 'Traceroute auf Node starten', type: 'boolean', role: 'button'},
              {id: 'getLocation', name: 'Standort anfordern', type: 'boolean', role: 'button'},
              {id: 'getTelemetry', name: 'Telemetrie anfordern', type: 'boolean', role: 'button'},
          ];
      
          nodeCommandStates.forEach(state => {
              var currentObject = {
                  "type": 'state',
                  "common": {
                      "name": state.name,
                      "type": state.type,
                      "read": true,
                      "write": true,
                      "role": state.role,
                  }
              };
              setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.command.' + state.id, currentObject);
          });
      } 
      
      function nodeIsKnown(id) {
          var nodeObject = getObject('0_userdata.0.Meshtastic.Nodes.' + id);
          if (nodeObject) { return true };
          return false;
      }
      
      function parseData(data) {
          // Split the data into lines
          const lines = data.trim().split('\n');
      
          // Extract the header line and data lines
          const headerLine = lines[2]; // Header line is the second line
          const dataLines = lines.slice(4, -1); // Skip the header, separator, and footer lines
      
          // Split the header line into keys
          const keys = headerLine.split('│').map(key => key.trim()).filter(key => key.length > 0);
      
          // Parse each data line into an object
          const objects = dataLines.map(line => {
              const values = line.split('│').map(value => value.trim()).filter(value => value.length > 0);
      
              // Skip lines that do not have the correct number of values
              if (values.length !== keys.length) {
                  return null;
              }
      
              let obj = {};
              keys.forEach((key, index) => {
                  obj[key] = values[index];
              });
              return obj;
          }).filter(obj => obj !== null); // Filter out null objects
      
          return objects;
      }
      
      function createChannels() {
          var baseChannel = {
              "type": 'channel',
              "common": {
                  "name": 'Meshtastic Server',
              }
          };
          setObject('0_userdata.0.Meshtastic', baseChannel);
      
          var baseChannel = {
              "type": 'channel',
              "common": {
                  "name": 'Nodes',
              }
          };
          setObject('0_userdata.0.Meshtastic.Nodes', baseChannel);
      
          var baseChannel = {
              "type": 'channel',
              "common": {
                  "name": 'Chats',
              }
          };
          setObject('0_userdata.0.Meshtastic.Chats', baseChannel);
      }
      
      function createChats() {
          chats.forEach(chatObj => {
              var chat = {
                  "type": 'channel',
                  "common": {
                      "name": chatObj.name,
                  }
              };
              setObject('0_userdata.0.Meshtastic.Chats.' + chatObj.id, chat);
              var chatCommandStates = [
                  {id: 'sendMessage', name: 'Nachricht an Chat senden', type: 'string', role: 'value'},
              ];
              chatCommandStates.forEach(state => {
                  var currentObject = {
                      "type": 'state',
                      "common": {
                          "name": state.name,
                          "type": state.type,
                          "read": true,
                          "write": true,
                          "role": state.role,
                      }
                  };
                  setObject('0_userdata.0.Meshtastic.Chats.' + chatObj.id + '.sendMessage', currentObject);
              });
          });
      }
      
      function registerEndpointListeners() {
          $('state[id=0_userdata.0.Meshtastic.Nodes.*.command.*]').each(function (id, i) {
              on({id: id, change: "any"}, function (obj) {
                  var id = obj.id;
                  var idParts = id.split('.');
                  var nodeId = idParts[4];
                  log(id, 'debug');
      
                  if (idParts[6] == 'getTelemetry' || idParts[6] == 'getLocation') {
                      
                      requestTelemetry(nodeId);
                  }
      
                  if (idParts[6] == 'sendPing') {
                      
                      sendPing(nodeId);
                  }
      
                  if (idParts[6] == 'sendTraceRoute') {
                      
                      startTraceroute(nodeId);
                  }
      
                  if (idParts[6] == 'sendMessage') {
                      var message = getState(id).val;
                      
                      sendDirectMessage(nodeId, message);
                  }
              });
          });
          $('state[id=0_userdata.0.Meshtastic.Chats.*.sendMessage]').each(function (id, i) {
              on({id: id, change: "any"}, function (obj) {
                  var id = obj.id;
                  var idParts = id.split('.');
                  var chatId = idParts[4];
                  var message = getState(id).val;
                  sendChatMessage(chatId, message);
              });
          });
      }
      
      function requestTelemetry(target, callback = null, counter = 0) {
          log('Requested Telemetry for node ' + target, 'info');
          exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --request-telemetry --dest \'!'+target+'\'', async function (error, result, stderr) {
              if (result.includes('Connected to radio')) {
                  log('Telemetry success', 'info');
                  if (callback) {
                      callback();
                  }
              } else {
                  // Erneut versuchen
                  log(result, 'error');
                  counter = counter + 1;
                  if (counter <= 5) {
                      requestTelemetry(target, callback, counter);
                  }
              }
          });
      }
      
      function startTraceroute(target, callback = null, counter = 0) {
          log('Start traceroute for node ' + target, 'info');
          exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --traceroute --dest \'!'+target+'\'', async function (error, result, stderr) {
              if (result.includes('Connected to radio')) {
                  log('Traceroute success', 'info');
                  if (callback) {
                      callback();
                  }
              } else {
                  // Erneut versuchen
                  log(result, 'error');
                  counter = counter + 1;
                  if (counter <= 5) {
                      startTraceroute(target, callback, counter);
                  }
              }
          });
      }
      
      function sendPing(target, callback = null, counter = 0) {
          log('Send ping for node ' + target, 'info');
          exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --sendping --dest \'!'+target+'\'', async function (error, result, stderr) {
              if (result.includes('Connected to radio')) {
                  log('Ping success', 'info');
                  if (callback) {
                      callback();
                  }
              } else {
                  // Erneut versuchen
                  log(result, 'error');
                  counter = counter + 1;
                  if (counter <= 5) {
                      sendPing(target, callback, counter++);
                  }
              }
          });
      }
      
      function sendDirectMessage(target, message, callback = null, counter = 0) {
          log('Send message for node ' + target + ' message: ' + message, 'info');
          exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --dest \'!'+target+'\' --sendtext "'+message+'"', async function (error, result, stderr) {
              if (result.includes('Connected to radio')) {
                  log('Message success', 'info');
                  if (callback) {
                      callback();
                  }
              } else {
                  // Erneut versuchen
                  log(result, 'error');
                  counter = counter + 1;
                  if (counter <= 5) {
                      sendDirectMessage(target, message, callback, counter);
                  }
              }
          });
      }
      
      function sendChatMessage(chatId, message, callback = null, counter = 0) {
          log('Send message for chat ' + chatId + ' message: ' + message, 'info');
          exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --ch-index '+chatId+' --sendtext "'+message+'"', async function (error, result, stderr) {
              if (result.includes('Connected to radio')) {
                  log('Message success', 'info');
                  if (callback) {
                      callback();
                  }
              } else {
                  // Erneut versuchen
                  log(result, 'error');
                  counter = counter + 1;
                  if (counter <= 5) {
                      sendChatMessage(chatId, message, callback, counter);
                  }
              }
          });
      }
      
      registerEndpointListeners();
      createChats();
      createChannels();
      updateNodes();
      
      setInterval(function() {
          updateNodes();
      },30000);
      
      
      
      M 1 Antwort Letzte Antwort
      0
      • T ToGe88

        @mark77 Moin, zwar schon ein bisschen älter der Beitrag aber ich antworte mal. Ich teste gerade auch ein wenig mit Meshtastic herum und habe mir ein Script erstellt welches über die Python Meshtastic CLI die Daten in den ioBroker holt. (Könnte man ggfs. auch zu einem Adapter umbauen zu einem späteren Zeitpunkt).

        Das Script erzeugt Datenpunkte um die Telemetrie Daten der Nodes zu überwachen, dafür werden diese alle 30 Sekunden vom Modul ausgelesen. Zudem ist es möglich Nachrichten an Chats, Direktnachrichten an Nodes, Traceroutes und Pings zu versenden. Der Empfang von Nachrichten ist aktuell nicht möglich. Ist alles noch mehr eine Bastellösung und im Testbetrieb. Die Integration ist aber schon sehr hilfreich wenn man zum Reichweitentest aus der Ferne z.B. Nachrichten von der "Basis" auslösen will oder prüfen möchte ob der mobile Node empfangen wird obwohl man dort kein ACK erhält. Möglich wäre auch eine Begrüßung von neuen Nodes auf dem Default Channel wenn sie in Reichweite der Basis mit ioBroker kommen ;)

        Wichtig ist das die Meshtastic CLI (https://meshtastic.org/docs/software/python/cli/installation/) für den User installiert wird unter welchem auch der ioBroker läuft. Ich nutze aktuell die Verbindung per WLAN, wenn es über die USB Schnittstelle laufen soll müsste man an den entsprechenden stellen die Befehle für exec anpassen.

        var deviceIp = '192.168.1.117';
        
        var chats = [
            { name: 'Default', id: 0 },
            { name: 'Benutzerkanal 1', id: 1 },
            { name: 'Benutzerkanal 2', id: 2 }
        ];
        
        
        function updateNodes() {
            exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --nodes', async function (error, result, stderr) {
                if (result.includes('Connected to radio')) {
                    var nodes = parseData(result);
                    handleNodes(nodes);
                }
            });
        }
        
        function handleNodes(nodes) {
            nodes.forEach(node => {
                node.ID = node.ID.replace("!", "");
                if (nodeIsKnown(node.ID)) {
                    updateNode(node);
                } else {
                    createNode(node);
                    setTimeout(function() {
                        updateNode(node);
                    },4000);
                }
            });
        }
        
        function updateNode(data) {
        var nodeInfoStates = [
                {id: 'id', name: 'NodeID', type: 'string', unit: null, log: false},
                {id: 'user', name: 'User', type: 'string', unit: null, log: false},
                {id: 'alias', name: 'Alias', type: 'string', unit: null, log: false},
                {id: 'location', name: 'Location', type: 'string', unit: null, log: true},
                {id: 'altitude', name: 'Altitude', type: 'number', unit: 'm', log: true},
                {id: 'chanUtil', name: 'Channel util.', type: 'number', unit: '%', log: true},
                {id: 'txAir', name: 'Tx air util.', type: 'number', unit: '%', log: true},
                {id: 'snr', name: 'SNR', type: 'number', unit: 'db', log: true},
                {id: 'channel', name: 'Channel', type: 'string', unit: null, log: false},
                {id: 'lastHeard', name: 'Last heard', type: 'string', unit: null, log: true},
                {id: 'battery', name: 'Battery', type: 'number', unit: '%', log: true}
            ];
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.id', data.N, true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.user', data.User, true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.alias', data.AKA, true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.location', data.Latitude.replace('°', '') + ', ' + data.Longitude.replace('°', ''), true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.altitude', parseFloat(data.Altitude.replace(' m', '')), true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.chanUtil', parseFloat(data['Channel util.'].replace('%', '')), true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.txAir', parseFloat(data['Tx air util.'].replace('%', '')), true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.snr', parseFloat(data.SNR.replace(' dB', '')), true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.channel', data.Channel, true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.lastHeard', data.LastHeard, true);
            setState('0_userdata.0.Meshtastic.Nodes.' + data.ID + '.info.battery', parseFloat(data.Battery.replace('%', '')), true);
        }
        
        function createNode(data) {
            log('creating new node', 'info');
            var newNode = {
                "type": 'channel',
                "common": {
                    "name": data.User,
                }
            };
            setObject('0_userdata.0.Meshtastic.Nodes.' + data.ID, newNode);
            createNodeStates(data.ID);
        }
        
        function createNodeStates(id) {
        
            var infoChannel = {
                "type": 'channel',
                "common": {
                    "name": 'Info',
                }
            };
            setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.info', infoChannel);
        
            var nodeInfoStates = [
                {id: 'id', name: 'NodeID', type: 'string', unit: null, log: false},
                {id: 'user', name: 'User', type: 'string', unit: null, log: false},
                {id: 'alias', name: 'Alias', type: 'string', unit: null, log: false},
                {id: 'location', name: 'Location', type: 'string', unit: null, log: true},
                {id: 'altitude', name: 'Altitude', type: 'number', unit: 'm', log: true},
                {id: 'chanUtil', name: 'Channel util.', type: 'number', unit: '%', log: true},
                {id: 'txAir', name: 'Tx air util.', type: 'number', unit: '%', log: true},
                {id: 'snr', name: 'SNR', type: 'number', unit: 'db', log: true},
                {id: 'channel', name: 'Channel', type: 'string', unit: null, log: false},
                {id: 'lastHeard', name: 'Last heard', type: 'string', unit: null, log: true},
                {id: 'battery', name: 'Battery', type: 'number', unit: '%', log: true}
            ];
        
            nodeInfoStates.forEach(state => {
                var currentObject = {
                    "type": 'state',
                    "common": {
                        "name": state.name,
                        "type": state.type,
                        "unit": state.unit,
                        "read": true,
                        "write": false,
                    }
                };
                setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.info.' + state.id, currentObject);
            });
        
        
            var commandChannel = {
                "type": 'channel',
                "common": {
                    "name": 'Command',
                }
            };
            setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.command', commandChannel);
        
            var nodeCommandStates = [
                {id: 'sendMessage', name: 'Direktnachricht an Node senden', type: 'string', role: 'value'},
                {id: 'sendPing', name: 'Ping an Node senden', type: 'boolean', role: 'button'},
                {id: 'sendTraceRoute', name: 'Traceroute auf Node starten', type: 'boolean', role: 'button'},
                {id: 'getLocation', name: 'Standort anfordern', type: 'boolean', role: 'button'},
                {id: 'getTelemetry', name: 'Telemetrie anfordern', type: 'boolean', role: 'button'},
            ];
        
            nodeCommandStates.forEach(state => {
                var currentObject = {
                    "type": 'state',
                    "common": {
                        "name": state.name,
                        "type": state.type,
                        "read": true,
                        "write": true,
                        "role": state.role,
                    }
                };
                setObject('0_userdata.0.Meshtastic.Nodes.' + id + '.command.' + state.id, currentObject);
            });
        } 
        
        function nodeIsKnown(id) {
            var nodeObject = getObject('0_userdata.0.Meshtastic.Nodes.' + id);
            if (nodeObject) { return true };
            return false;
        }
        
        function parseData(data) {
            // Split the data into lines
            const lines = data.trim().split('\n');
        
            // Extract the header line and data lines
            const headerLine = lines[2]; // Header line is the second line
            const dataLines = lines.slice(4, -1); // Skip the header, separator, and footer lines
        
            // Split the header line into keys
            const keys = headerLine.split('│').map(key => key.trim()).filter(key => key.length > 0);
        
            // Parse each data line into an object
            const objects = dataLines.map(line => {
                const values = line.split('│').map(value => value.trim()).filter(value => value.length > 0);
        
                // Skip lines that do not have the correct number of values
                if (values.length !== keys.length) {
                    return null;
                }
        
                let obj = {};
                keys.forEach((key, index) => {
                    obj[key] = values[index];
                });
                return obj;
            }).filter(obj => obj !== null); // Filter out null objects
        
            return objects;
        }
        
        function createChannels() {
            var baseChannel = {
                "type": 'channel',
                "common": {
                    "name": 'Meshtastic Server',
                }
            };
            setObject('0_userdata.0.Meshtastic', baseChannel);
        
            var baseChannel = {
                "type": 'channel',
                "common": {
                    "name": 'Nodes',
                }
            };
            setObject('0_userdata.0.Meshtastic.Nodes', baseChannel);
        
            var baseChannel = {
                "type": 'channel',
                "common": {
                    "name": 'Chats',
                }
            };
            setObject('0_userdata.0.Meshtastic.Chats', baseChannel);
        }
        
        function createChats() {
            chats.forEach(chatObj => {
                var chat = {
                    "type": 'channel',
                    "common": {
                        "name": chatObj.name,
                    }
                };
                setObject('0_userdata.0.Meshtastic.Chats.' + chatObj.id, chat);
                var chatCommandStates = [
                    {id: 'sendMessage', name: 'Nachricht an Chat senden', type: 'string', role: 'value'},
                ];
                chatCommandStates.forEach(state => {
                    var currentObject = {
                        "type": 'state',
                        "common": {
                            "name": state.name,
                            "type": state.type,
                            "read": true,
                            "write": true,
                            "role": state.role,
                        }
                    };
                    setObject('0_userdata.0.Meshtastic.Chats.' + chatObj.id + '.sendMessage', currentObject);
                });
            });
        }
        
        function registerEndpointListeners() {
            $('state[id=0_userdata.0.Meshtastic.Nodes.*.command.*]').each(function (id, i) {
                on({id: id, change: "any"}, function (obj) {
                    var id = obj.id;
                    var idParts = id.split('.');
                    var nodeId = idParts[4];
                    log(id, 'debug');
        
                    if (idParts[6] == 'getTelemetry' || idParts[6] == 'getLocation') {
                        
                        requestTelemetry(nodeId);
                    }
        
                    if (idParts[6] == 'sendPing') {
                        
                        sendPing(nodeId);
                    }
        
                    if (idParts[6] == 'sendTraceRoute') {
                        
                        startTraceroute(nodeId);
                    }
        
                    if (idParts[6] == 'sendMessage') {
                        var message = getState(id).val;
                        
                        sendDirectMessage(nodeId, message);
                    }
                });
            });
            $('state[id=0_userdata.0.Meshtastic.Chats.*.sendMessage]').each(function (id, i) {
                on({id: id, change: "any"}, function (obj) {
                    var id = obj.id;
                    var idParts = id.split('.');
                    var chatId = idParts[4];
                    var message = getState(id).val;
                    sendChatMessage(chatId, message);
                });
            });
        }
        
        function requestTelemetry(target, callback = null, counter = 0) {
            log('Requested Telemetry for node ' + target, 'info');
            exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --request-telemetry --dest \'!'+target+'\'', async function (error, result, stderr) {
                if (result.includes('Connected to radio')) {
                    log('Telemetry success', 'info');
                    if (callback) {
                        callback();
                    }
                } else {
                    // Erneut versuchen
                    log(result, 'error');
                    counter = counter + 1;
                    if (counter <= 5) {
                        requestTelemetry(target, callback, counter);
                    }
                }
            });
        }
        
        function startTraceroute(target, callback = null, counter = 0) {
            log('Start traceroute for node ' + target, 'info');
            exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --traceroute --dest \'!'+target+'\'', async function (error, result, stderr) {
                if (result.includes('Connected to radio')) {
                    log('Traceroute success', 'info');
                    if (callback) {
                        callback();
                    }
                } else {
                    // Erneut versuchen
                    log(result, 'error');
                    counter = counter + 1;
                    if (counter <= 5) {
                        startTraceroute(target, callback, counter);
                    }
                }
            });
        }
        
        function sendPing(target, callback = null, counter = 0) {
            log('Send ping for node ' + target, 'info');
            exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --sendping --dest \'!'+target+'\'', async function (error, result, stderr) {
                if (result.includes('Connected to radio')) {
                    log('Ping success', 'info');
                    if (callback) {
                        callback();
                    }
                } else {
                    // Erneut versuchen
                    log(result, 'error');
                    counter = counter + 1;
                    if (counter <= 5) {
                        sendPing(target, callback, counter++);
                    }
                }
            });
        }
        
        function sendDirectMessage(target, message, callback = null, counter = 0) {
            log('Send message for node ' + target + ' message: ' + message, 'info');
            exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --dest \'!'+target+'\' --sendtext "'+message+'"', async function (error, result, stderr) {
                if (result.includes('Connected to radio')) {
                    log('Message success', 'info');
                    if (callback) {
                        callback();
                    }
                } else {
                    // Erneut versuchen
                    log(result, 'error');
                    counter = counter + 1;
                    if (counter <= 5) {
                        sendDirectMessage(target, message, callback, counter);
                    }
                }
            });
        }
        
        function sendChatMessage(chatId, message, callback = null, counter = 0) {
            log('Send message for chat ' + chatId + ' message: ' + message, 'info');
            exec('/home/iobroker/.local/bin/meshtastic --host '+deviceIp+' --ch-index '+chatId+' --sendtext "'+message+'"', async function (error, result, stderr) {
                if (result.includes('Connected to radio')) {
                    log('Message success', 'info');
                    if (callback) {
                        callback();
                    }
                } else {
                    // Erneut versuchen
                    log(result, 'error');
                    counter = counter + 1;
                    if (counter <= 5) {
                        sendChatMessage(chatId, message, callback, counter);
                    }
                }
            });
        }
        
        registerEndpointListeners();
        createChats();
        createChannels();
        updateNodes();
        
        setInterval(function() {
            updateNodes();
        },30000);
        
        
        
        M Offline
        M Offline
        mark77
        schrieb am zuletzt editiert von
        #3

        @toge88 sehr schön!

        Ein Adapter wäre natürlich traumhaft.

        Bei meinem Modul (diymore ESP32 LoRa [Amazon]) ärgert mich im Moment, dass wenn er die WLAN Verbindung verloren hat, neu gestartet werden muss.
        Wie ist das bei dir?

        Gruß,
        Mark

        1 Antwort Letzte Antwort
        0
        • M mark77

          Moin,

          seit ein paar Tagen experimentiere ich mit meshtastic (meshtastic.org).

          Im Forum wollte ich mal schauen ob es gleichgesinnte gibt, die das System erfolgreich in ioBroker eingebunden haben und wenn ja, wie?

          Gruß,
          Mark

          J Offline
          J Offline
          JimmyBondi
          schrieb am zuletzt editiert von
          #4

          Ich reihe mich mal hier ein, auch wenn der Thread schon über 1 Jahr alt ist.

          Spiele ebenfalls aktuell ein wenig mit Mashtastic herum.
          Ein Adapter wäre schon prima.

          @ToGe88
          Danke für das Script !
          Habe alles erfolgreich installieren können und das Script läuft so weit.
          Allerdings werden mir nur Nodes angelegt, die in der App als "unknown" deklariert sind.
          Wenn ich mir die Node Liste in der Bash (via CLI) anzeigen lassen, dann haben diese den Channel 0 und bei allen anderen ist der Channel leer.
          Hast Du da ggf eine aktuellere Variante ?

          1 Antwort Letzte Antwort
          0
          Antworten
          • In einem neuen Thema antworten
          Anmelden zum Antworten
          • Älteste zuerst
          • Neuste zuerst
          • Meiste Stimmen


          Support us

          ioBroker
          Community Adapters
          Donate

          905

          Online

          32.4k

          Benutzer

          81.5k

          Themen

          1.3m

          Beiträge
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
          ioBroker Community 2014-2025
          logo
          • Anmelden

          • Du hast noch kein Konto? Registrieren

          • Anmelden oder registrieren, um zu suchen
          • Erster Beitrag
            Letzter Beitrag
          0
          • Home
          • Aktuell
          • Tags
          • Ungelesen 0
          • Kategorien
          • Unreplied
          • Beliebt
          • GitHub
          • Docu
          • Hilfe