Devicemonitoring etwas anders

Ich hab mich mit dem Thema schon länger befasst. Ich hatte Domotz im Einsatz. Es funktioniert toll, aber warum soll ich dafür bezahlen, wenn ich das selber auch machen kann. Meine Ansprüche sind ja nicht sehr hoch. Gut, IPS erkennt keine neuen Geräte, aber egal.
Ich hab mir dann den „Device Monitor“ in IPS installiert. Funktioniert auch. Geräte hinzugefügt und auch Benachrichtigungen eingebaut, wenn mal ein Device nicht geantwortet hat. Leider ist es aber so, dass es nichts heißt, wenn mal ein Ping verloren geht. Das passiert schon mal. Auch bei zwei Pings mach ich mir noch keine Sorgen. Also war diese Lösung unbefriedigend, weil ich zugemüllt wurde.
Auch bin ich kein Fan von Hardcodierung im Backend. Das ist unflexibel. Also musste etwas anderes her.
Ich überlegte mir also, wie ich es mit den Möglichkeiten von IPS und PHP anstellen könnte, einen einfachen aber doch funktionalen Monitor zu machen. Es sollte möglich sein, im Webfront Geräte hinzufügen, ändern und löschen. Eine Übersicht braucht es auch und natürlich eine Benachrichtigung, wenn ein als wichtig markiertes Gerät nicht antwortet.
Und ja, ich habe es mit meinen beschränkten PHP Kenntnissen geschafft.
Zentrale Basis ist eine Stringvariable, die mir einen JSON String vorhält, wo meine Geräte mit allen notwendigen Informationen wie IP, Name, Letzte Änderung, Ping Status und ob es wichtig ist oder nicht gespeichert sind.


Weiters brauhte ich noch deine Dummy-Instanz unter derer ich diverse Variablen für die Erfassung der Daten definiert hab

Das Aktionskript beim Button Aktion speichert alles ab

<?php
include(IPS_GetScriptFile(31314/*Skript Netzwerkstatus*/));
SetValue($_IPS['VARIABLE'], $_IPS['VALUE']);

if (getvalue(50396/*IP Adresse ist nicht leer*/) != "" and getvalue(57084/*Name ist nicht leer*/) !="")
{
    Switch ($_IPS['VALUE']){
        case 1: DevEintragen (getvalue(50396/*IP*/),getvalue(57084/*Name*/),getvalue(14117/*Benachrichtigen bei Fehler*/),true);
                break;
        case 2: DevEintragen (getvalue(50396/*IP*/),getvalue(57084/*Name*/),getvalue(14117/*Benachrichtigen bei Fehler*/),false);
                break;
        case 3: DevLoeschen (getvalue(50396/*IP*/));
                break;
    }
    /*Wenn alles gespeichert ist, IP und Name zurücksetzen*/
    setvalue(50396/*IP*/,"192.168.32.");
    setvalue(57084/*Name*/,"");
    DevListe();/*HTML Tabelle aufbauen*/
}
else
{
    WFC_SendNotification(56676/*Home*/,"Device Monitor","IP oder Gerätename fehlt!","",0);/*Fehlermeldung bei leerer IP oder leerem Namen*/
}

Das Skript „Netzwerkstatus“ enthält alle Funktionen

<?php
/*Neues Device eintragen und ändern*/
function DevEintragen ($IP,$Beschreibung,$Wichtig,$Neu)
{
    IPS_SetEventActive(32486,false);/*Ereignis für Ping während dem Eintragen deaktivieren*/
    $Liste=json_decode(getvalue(32307/*GerätelisteJSON*/),true);
    $Liste[$IP]["IP"]=$IP;
    $Liste[$IP]["Name"]=$Beschreibung;
    if ($Wichtig)
    {
        $Liste[$IP]["Wichtig"]="J";
    }
    else
    {
        $Liste[$IP]["Wichtig"]="N";
    }
    if ($Neu) $Liste[$IP]["LastChange"]=0;
    if ($Neu) $Liste[$IP]["Status"]="NA";
    if ($Neu) $Liste[$IP]["Meldung"]="N";
    ksort($Liste);/*nach IP sortieren*/
    setvalue(32307/*GerätelisteJSON*/,json_encode($Liste));
    IPS_SetEventActive(32486,true);/*Ping wieder aktivieren*/
}
/*Device löschen*/
function DevLoeschen ($IP)
{
    IPS_SetEventActive(32486,false);/*Ereignis für Ping während Löschen deaktiveren*/
    $Liste=json_decode(getvalue(32307/*GerätelisteJSON*/),true);
    unset($Liste[$IP]);
    ksort($Liste);/*nach IP sortieren*/
    setvalue(32307/*GerätelisteJSON*/,json_encode($Liste));
    IPS_SetEventActive(32486,true);/*Ping wieder aktivieren*/
}
/*HTML Tabelle erstellen*/
function DevListe()
{
    $Zeile=1;
    $Farbe="";
    $FarbeWichtig="";
    $Text="";
    $Liste=json_decode(getvalue(32307)/*GerätelisteJSON*/,true);
    $Liste_HTML = "";
    $Liste_HTML = $Liste_HTML."<table border=\"1\" style=\"width:100%\">";
    $Liste_HTML = $Liste_HTML."<tr>";
    $Liste_HTML = $Liste_HTML."<th><center>Zeile</center></th><th><center>IP</center></th><th><center>Gerät</center></th><th><center>Letzte Änderung</center></th><th><center>Ping</center></th><th><center>Status</center></th>";
    $Liste_HTML = $Liste_HTML."</tr>";
    foreach ($Liste as $Device)
    {
        switch ($Device["Status"]){
            case "NA":  $Farbe=""; $Text="";
                        break;
            case "OK":  $Farbe="green"; $Text="Ok";
                        break;
            case "NOK": $Farbe="red"; $Text="Fehler";
                        break;
        }
        if ($Device["Wichtig"] == "J") {
            $FarbeWichtig="blue";
        }
        else
        {
            $FarbeWichtig="";
        }
        $Liste_HTML = $Liste_HTML."<tr>";
        $Liste_HTML = $Liste_HTML. "<td style=\"background-color:".$FarbeWichtig."\">".$Zeile."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\">".$Device["IP"]."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\">".$Device["Name"]."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\"><center>".date("d.m.Y H:i:s",$Device["LastChange"])."</center></td>
                                    <td style=\"background-color:".$Farbe."\"><center>".$Text."</center></td>";
        if ($Device["Status"] == "NOK")
        {
            $DownTime = time()-$Device["LastChange"];
            if ($DownTime<=60){$Text="HBL"; $Farbe="blue";}/*Heartbeat lost - noch kein Problem*/
            if ($DownTime>=61 and $DownTime<=90){$Text="CL";$Farbe="orange";}/*noch immer keine Verbindung - keine Panik*/
            if ($DownTime>=91){$Text="DWN";$Farbe="red";}/*nach 90 Sekunden ist das Ding Down*/
        }
        else
        {
            $Text="UP";
            $Farbe="green";
        }
        $Liste_HTML = $Liste_HTML."<td style=\"background-color:".$Farbe."\"><center>".$Text."</center></td>";
        $Zeile++;
    }
    $Liste_HTML = $Liste_HTML."</table>";
    setvalue(55639/*Netzwerkstatus HTML Variable*/,$Liste_HTML);
}
/*Ping ausführen*/
function DevPing()
{
    IPS_SetDisabled(34099,true);/*Button zum Speichern deaktivieren*/
    $Liste=json_decode(getvalue(32307/*GerätelisteJSON*/),true);
    $Timeout=getvalue(55711/*Pingtimeout lesen*/);
    foreach ($Liste as &$Device)
    {
        $AktuellerStatus=$Device["Status"];
        if (sys_ping($Device["IP"],$Timeout))/*sys_ping ist eine Symcon Funktion*/
        {
            $Device["Status"]="OK";
            if ($AktuellerStatus != $Device["Status"]) $Device["LastChange"]=time();
            if ($Device["Meldung"] == "J") Telegram_SendTextToAll(58283,$Device["Name"]. " antwortet wieder!"); /*Meldung wenn Device wieder erreichbar*/
            $Device["Meldung"] = "N";/*Meldungserkennung zurücksetzen*/
        }
        else
        {
            $Device["Status"]="NOK";
            if ($AktuellerStatus != $Device["Status"]) $Device["LastChange"]=time();
             if (time()-$Device["LastChange"] >90 and $Device["Wichtig"] == "J" and $Device["Meldung"] == "N")
             {
                 Telegram_SendTextToAll(58283,$Device["Name"]. " antwortet nicht!"); /*Meldung Device ist nicht erreichbar*/
                 $Device["Meldung"] = "J";/*Meldung auf J ändern, damit nur einmal gemeldet wird*/
             }
        }
        if ($Device["Wichtig"]=="") $Device["Wichtig"] = "N";
        if ($Device["Meldung"]=="") $Device["Meldung"] = "N";

    }    
    unset($Device);
    setvalue(32307/*GerätelisteJSON*/,json_encode($Liste));
    IPS_SetDisabled(34099,false);/*Button wieder aktivieren*/
}

Das letze Skript ist ein Dreizeiler. Das startet den Ping und aktualisiert die HTML-Tabelle

<?php

include(IPS_GetScriptFile(31314/*Skript Neztwerkstatus*/));
DevPing();
DevListe();

Für dieses Skript hab ich eine Ereignis alle 30 Sekunden definiert.
Im Webfront schaut es dann so aus
Eingabe und Änderung von Geräten

Blau hinterlegte Zeilen zeigen „wichtige“ Geräte an. Ist so ein Gerät nicht erreichbar, bekomme ich eine Meldung.

Kommentare sind jederzeit gerne willkommen!

Ich hab das jetzt komplett imgedreht. Jetzt kommt es schon sehr nahe an die Funktionalitt von Domotz heran. Ohne SNMP, das brauch ich nicht.
Wie kam es dazu. Mir hat das keine Ruhe gelassen, wie die das bei Domotz machen. Das Netzwerk in relativ kurzer Zeit zu scannen. Also hab ich mich auf die Suche gemacht und tatschlich hat einer mit Nagios den Traffic verfolgt. Stichworte waren dann ARP und nmap.
Nmap angeschaut, getestet und für gut befunden. Namp liest mir in etwa 15 Sekunden das Netzwerk durch und erzeugt mir dann eine XML, die ich weiterverarbeite. Ich bekomme neben IP auch die MAC und als Zuckerl den Hersteller aufgrund der MAC. Das ganze wird dann in einem Skript verarbeitet - nona. Die Daten selbst speichere ich der Einfachheit halber auf einem SQL Server.
Mit dieser Methode bekomme ich nicht nur jene Geräte die eine fixe IP haben, sonder natürlich auch alle anderen. Schlüssel ist in diesem Fall die MAC. Die IP in der Datenbank wird entsprechend geändert, wenn das Gerät eine neue IP bekommt. Die Änderung von diversen Daten mach ich in phpMyAdmin. Das ist einfacher, da ich ja nicht täglich den Namen oder ähnliches ändere. Suche nach Name, IP und MAC und auch Sortierung und Filterung sind eingebaut.
Einen kleinen Schönheitsfehler habe ich noch. Da ich es nicht geschafft habe, nmap aus dem Skript aufzurufen, habe ich eine Batch Datei erstellt, die das macht und diese wird über den Taskplaner Jede Minute gestartet. Damit Symcon das auch mitbekommt, rufe ich per wget einen WebHook auf. Dieser Hook startet das Skript. Vielleicht hat da noch jemand einen Tip für mich. Ich hab etliches probiert.

Die Batch

@echo off
del C:\ProgramData\Symcon\scripts\scanner.xml /s /q
\\NAS469L\Symcon
map
map -n -sn -vv 192.168.32.0/24 -oX C:\ProgramData\Symcon\scripts\scanner.xml
\\NAS469L\Symcon
map\wget http://ipsserver:3777/hook/nmap

Das „Hauptskript“

<?php

function readxml()
{
    $sqlserver=getvalue(59311);
    $user=getvalue(41755);
    $password=getvalue(17356);
    $database=getvalue(33225);
    /*letzten Scan einlesen*/
    $path = "scanner.xml"; 
    $xmlfile = file_get_contents($path); 
    $new = simplexml_load_string($xmlfile); 
    $con = json_encode($new); 
    $newArr = json_decode($con, true);
    $lastscan=array();
    $devicelist=array();
    $iptemp="";
    foreach ($newArr["host"] as $hostlist)
    {
        if ($hostlist["status"]["@attributes"]["state"] == "up")
        {
            if (isset($hostlist["address"][1]["@attributes"]["addr"]))
            {
                $mac=$hostlist["address"][1]["@attributes"]["addr"]; /*localhost liefert keine mac*/
            }
            else
            {
                $mac=$hostlist["status"]["@attributes"]["reason"]; /*localhost*/
            }
            $lastscan[$mac]=$mac;
            $lastscan[$mac]=array();
            $lastscan[$mac]["mac"]=$mac;
            /*localhost sieht anders aus*/
            if (isset ($hostlist["address"][0]["@attributes"]["addr"]))
            {
                $lastscan[$mac]["ip"]=$hostlist["address"][0]["@attributes"]["addr"];
            }
            else
            {
                $lastscan[$mac]["ip"]=$hostlist["address"]["@attributes"]["addr"];
            }
            $lastscan[$mac]["status"]=$hostlist["status"]["@attributes"]["state"];
            if (isset($hostlist["address"][1]["@attributes"]["vendor"])){
                $lastscan[$mac]["vendor"]=$hostlist["address"][1]["@attributes"]["vendor"];
            }
            else 
            {
                $lastscan[$mac]["vendor"]="";
            }
        }
    }
    $dbhandler=mysqli_connect($sqlserver,$user,$password,$database);
    /*alle auf down setzen und downcounter um eins erhöhen*/
    $allhosts = mysqli_query($dbhandler,"select mac,downcounter,important from hosts");
    while($row = mysqli_fetch_object($allhosts))
    {
        $downcounter=$row->downcounter; /*Anzahl durchläufe down*/
        $downcounter++;
        mysqli_query($dbhandler,"update hosts set downcounter='".$downcounter."',up=0 where mac='".$row->mac."'");
    }
    foreach ($lastscan as $host)
    {
        $check=mysqli_query($dbhandler,"select mac from hosts where mac='".$host["mac"]."'");
        $exist=($check->num_rows >0?true:false);
        if ($exist)
        {
            /*Datensatz vorhanden ändern*/
            $iptemp=$host["ip"];
            $iparray=explode(".",$iptemp);
            $iptemp=str_pad($iparray[0],3,"0",STR_PAD_LEFT).".".
                    str_pad($iparray[1],3,"0",STR_PAD_LEFT).".".
                    str_pad($iparray[2],3,"0",STR_PAD_LEFT).".".
                    str_pad($iparray[3],3,"0",STR_PAD_LEFT);
                    $test=str_pad($iparray[3],3,"0",STR_PAD_LEFT);
            mysqli_query($dbhandler,"update hosts set ip='".$iptemp."',up=1 where mac='".$host["mac"]."'"); /*eventuell IP ändern und status auf up*/
            $data=mysqli_query($dbhandler,"select important,notify,name from hosts where mac='".$host["mac"]."'");
            $value=mysqli_fetch_object($data);
            $important=($value->important==1?true:false); /*ob wichtig*/
            $notify=($value->notify==1?true:false); /*ob meldung verschickt*/
            $name=$value->name; /*Name holen*/
            if ($notify)
            {
                 Telegram_SendTextToAll(58283,$name. " antwortet wieder!");
                 mysqli_query($dbhandler,"update hosts set notify=0 where mac='".$host["mac"]."'"); /*Benachrichtigung zurücksetzen*/
            }
            mysqli_query($dbhandler,"update hosts set downcounter='0',lastup='".date("Y-m-d H:i:s",time())."' where mac='".$host["mac"]."'");
        }
        else
        {
            mysqli_query($dbhandler,
            "insert into hosts (mac,ip,name,important,firstseen,lastup,up,notify,vendor) values ('".
            $host["mac"]."','".
            $host["ip"]."','".
            $host["vendor"]."','".
            "0"."','".
            date("Y-m-d H:i:s",time())."','".
            date("Y-m-d H:i:s",time())."','".
            "1"."','".
            "0"."','".
            $host["vendor"]."')");
            Telegram_SendTextToAll(58283,"Neues Gerät gefunden: ".$host["mac"]." ".$host["ip"]." ".$host["vendor"]);
        }
    }
    $allhosts = mysqli_query($dbhandler,"select mac,downcounter,important,notify,name from hosts where up='0' and important='1' and notify='0' and downcounter='3'");
    while($row = mysqli_fetch_object($allhosts))/*Benachrichtigung der important devices*/
    {
        $name=$row->name; /*Name holen*/
        mysqli_query($dbhandler,"update hosts set notify='1' where mac='".$row->mac."'");
        Telegram_SendTextToAll(58283,$name. " antwortet nicht!"); /*Meldung Device ist nicht erreichbar*/
    }
    mysqli_close($dbhandler);
}
function generatetable()
{
    $sort="";
    switch(getvalue(34021)){
        case 1: $sort="mac";break;
        case 2: $sort="ip";break;
        case 3: $sort="name";break;
        case 4: $sort="important";break;
        case 5: $sort="firstseen";break;
        case 6: $sort="lastup";break;
        case 7: $sort="up";break;
        case 8: $sort="vendor";break;
        default:$sort="ip";
    }
    $ascdsc="";
    switch(getvalue(40698)){
        case 1: $ascdsc="ASC";break;
        case 2: $ascdsc="DESC";break;
        default:$ascdsc="ASC";
    }
    $where="";
    switch(getvalue(14624)){
        case 1: $where="";break;
        case 2: $where="where important=1";break;
        case 3: $where="where important=0";break;
        case 4: $where="where up=1";break;
        case 5: $where="where up=0";break;
        default:$where="";
    }
    /*suche IP*/
    $sucheip=getvalue(47245);
    if ($sucheip<>"" ){
        if($where==""){
            $where="where ip like '%".$sucheip."%'";
        }
        else
        {
            $where=$where." or ip like '%".$sucheip."%'";
        }
        setvalue(47245,"");
    }
    /*suche MAC*/
    $suchemac=getvalue(54294);
    if ($suchemac<>"" ){
        if($where==""){
            $where="where mac like '%".$suchemac."%'";
        }
        else
        {
            $where=$where." or mac like '%".$suchemac."%'";
        }
        setvalue(54294,"");
    }    
    /*suche Name*/
    $suchename=getvalue(28483);
    if ($suchename<>"" ){
        if($where==""){
            $where="where name like '%".$suchename."%'";
        }
        else
        {
            $where=$where." or name like '%".$suchename."%'";
        }
        setvalue(28483,"");
    }      
    $Zeile=1;
    $sqlserver=getvalue(59311);
    $user=getvalue(41755);
    $password=getvalue(17356);
    $database=getvalue(33225);
    $dbhandler=mysqli_connect($sqlserver,$user,$password,$database);
    $allhosts = mysqli_query($dbhandler,"select * from hosts ".$where." order by ".$sort." ".$ascdsc);
    $Liste_HTML = "";
    $Liste_HTML = $Liste_HTML."<table border=\"1\" style=\"width:100%\">";
    $Liste_HTML = $Liste_HTML."<tr>";
    $Liste_HTML = $Liste_HTML."<th><center>Zeile</center></th><th><center>IP</center></th><th><center>MAC</center></th><th><center>Gerät</center></th><th><center>Hersteller</center></th><th><center>Erkannt</center></th><th><center>zul. Online</center></th><th><center>Ping</center></th><th><center>Status</center></th>";
    $Liste_HTML = $Liste_HTML."</tr>";
    while($row = mysqli_fetch_object($allhosts))
    {
        switch ($row->up){
            case 1:  $Farbe="green"; $Text="Ok";
                        break;
            case 0: $Farbe="red"; $Text="Fehler";
                        break;
        }
        if ($row->important == 1) {
            $FarbeWichtig="blue";
        }
        else
        {
            $FarbeWichtig="";
        }
        $Liste_HTML = $Liste_HTML."<tr>";
        $Liste_HTML = $Liste_HTML. "<td style=\"background-color:".$FarbeWichtig."\">".$Zeile."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\">".$row->ip."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\">".$row->mac."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\">".$row->name."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\">".$row->vendor."</td>
                                    <td style=\"background-color:".$FarbeWichtig."\"><center>".$row->firstseen."</center></td>
                                    <td style=\"background-color:".$FarbeWichtig."\"><center>".$row->lastup."</center></td>
                                    <td style=\"background-color:".$Farbe."\"><center>".$Text."</center></td>";
        if ($row->up == 0)
        {
            if ($row->downcounter==1){$Text="HBL"; $Farbe="blue";}/*Heartbeat lost - noch kein Problem*/
            if ($row->downcounter==2){$Text="CL";$Farbe="orange";}/*noch immer keine Verbindung - keine Panik*/
            if ($row->downcounter>2){$Text="DWN<br>".$row->downcounter;$Farbe="red";}/*nach 90 Sekunden ist das Ding Down*/
        }
        else
        {
            $Text="UP";
            $Farbe="green";
        }
        $Liste_HTML = $Liste_HTML."<td style=\"background-color:".$Farbe."\"><center>".$Text."</center></td>";
        $Zeile++;
    }
    $Liste_HTML = $Liste_HTML."</table>";
    setvalue(13373/*Netzwerkstatus HTML Variable*/,$Liste_HTML);   
    mysqli_close($dbhandler);
}

Das Skript, das vom WebHook aufgerufen wird

<?php
include(IPS_GetScriptFile(57045));
readxml();
generatetable();

Und so sieht das dann in IPS aus

Ich bekomme auf Telegram Benachrichtigungen wenn ein Device down oder up geht und wenn ein neues Gerät erkannt wurde.

Hallo hfichtinger,

möchte gerne mal dein Device Monitor aus dem ersten Beitrag testen.
Ich habe teilwese Probleme in dem Script „Netzwerkstatus“. Ick kann die ID: 34099 nicht zuordnen.

Kanns du noch den Profil von der Aktion einen Scrennshot machen?

Gruß

Ich hab die alte Version schon gelöscht. Aber das ist der Button zum Speichern/Änder/Löschen. Ist eine Integer die als Button angezeigt wird mit verschiedenen Werten im Profl. Das hab ich deswegen während der Verarbeitung deaktiviert, damit es zu keinen Inkonsistenzen kommt.


Der Aktion Button ist das.

Hi,

jetzt habe ich es verstanden :slight_smile:
Danke

Gruß

Hi hfichtinger,

Device Monitor läuft. Bekomme aber keine Infos bei Störung.
Da ich Telegram auch habe, musste ich ja nur die ID ändern.

Kommen aber keine Nachrichten.

Gruß

Meldungen kommen nur, wenn ein Device als Wichtig markiert wurde. Eventuell liegt da der Fehler. Und auch erst nach etwa 90 Sekunden. Das kannst du aber ändern in dem du statt 90 einen höheren Wert nimmst. Bei mir ist der Job alle 30 Sekunden gelaufen. also nach 1,5 Minuten ist das Ding laut meiner Definition down. Du kannst den Json String auch manuell in einem Editor bearbeiten. Einfach den Wert herauskopieren und dann wieder rein damit.