repats blog Thoughts of a digital native

18Mai/120

Pruefen ob ein Computer online ist mit ping und perl

Ich habe bei der Arbeit ein kleines Perl-Skript geschrieben, welches prüfen sollte, ob bestimmte Computer in bestimmten Räumen(also IP-Ranges) noch online sind oder schon automatisch ausgestellt wurden. Dieses Skript sendet ein Paket über ping und guckt dann, ob es ein packetloss gibt. Im Grunde wäre das in der Bash besser gewesen, aber so kann man das, wenn man es ein bisschen anpasst, auch unter anderen OS verwenden.

Code

# The string containsPacketLoss is searching for
$packetloss = "100% packet loss";
# Init
$returnval = "";

print "\nCheck if Computers are online...\n";

# Scan IP-Range
for (my $i = 1; $i <=255; $i++) {
	# c = one package, w = deadline, q = quiet
        $ipcmd = "ping -c1 -q -w1 169.254.1." . $i;
        # execute and retreive output
        $returnval = `$ipcmd`;
        if (containsPacketLoss() == 0) {
            # output
            print "Computer  with IP 169.254.1." . $i . "is still online.\n";
            # write log file
	    system("echo Computer with IP 169.254.1.". $i . localtime(time) . " ONLINE >> /home/user/log");
        }
}

sub containsPacketLoss(){
	# check by RegEx if the string specified above is in the returnvalue
	# of the ping command
	if ($returnval =~ m/$packetloss/ ){
                return 1;
        }
        return 0;
}

Download

flattr this!

18Mai/120

Arduino Ethernet Shield und LM35DZ Temperatursensor

Das ist ein Projekt was bei mir bestimmt schon 2 Jahre rumliegt. Vielleicht wird es auch noch erweitert.

Hardware
Einen Arduino bekommt man für knapp 25€ bei diversen Shops im Internet, im Laden hab ich sie bis jetzt nur überteuert als Paket bei Conrad gesehen. Das Ethernet Shield bekommt man auch für ~$10 bei ebay. Den LM35DZ Temperatursensor hab ich für ca. 4€ bei Conrad gekauft. Der Rest (Lötsachen, Kabel, Schrumpfschläuche) ist Zubehör, das hier so rumlag.
Gemäss dem Datenblatt habe ich den Temperatursensor über ein paar angelötete Kabel an das Breadboard aufgesteckt. Die Beinchen habe ich mit Schrumpfschläuchen versehen, damit sie nicht aus versehen gegeneinander kommen können. Ich überlege gerade noch es mit Heisskleber abzudichten, so dass der Sensor nach draussen kann.

Software
Ich setze ein bisschen Grundwissen der Programmierung voraus. Vor allem, wer C kann, sollte hier keine Schwierigkeiten haben. Ist auch nicht schwer. Es gibt 2 Funktionen, setup() und loop(), die entsprechend ihrem Namen genau das tun. Für fast alles hat schonmal jemand eine library geschrieben, man muss quasi nur noch den Bastelkasten nehmen und zusammenstecken. Für das Ethernet Shield gibt es natürlich eine library, die das im Grunde recht simpel macht. Man bindet einfach die libraries dafür ein:

#include <Ethernet.h>
#include <SPI.h>

und kann dann global mit

byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = {
192,168,1,5 };
byte gateway[] = {
192, 168, 1, 1};
byte dns[] = {
192, 168, 1, 1};
byte subnet[] = {
255, 255, 255, 0 };

die entsprechenden Optionen setzen. Am besten die IP-Adresse so wählen, dass man nicht mit dem DHCP Server korreliert. Dann kommt noch eine kurze Initialisierung:

Server server(80);

Nebenbei habe ich den input pin für die Temperatur gesetzt und eine globale Variabale dafür angelegt:

const int apin = A3;
float temperature;

In setup() wird dann mit folgenden Befehlen der Webserver gestartet:

Ethernet.begin(mac, ip, dns, gateway);
server.begin();

Hier setze ich die serielle Verbindung auf 9600 Baud und definiere den oben spezifierten Pin als INPUT:

Serial.begin(9600);
pinMode(apin,INPUT);

Als nächstes kommt loop(). Hier definier ich eine Variable in die der rohe Input gespeichert wird. Die rechnet man dann gemäß einer Formel um, die ich im Internet gefunden hab. Zum Test habe ich eine Ausgabe auf der seriellen Console eingestellt. Die findest man in der Arduino IDE unter Tools. Jenachdem ob man ihn an 3.3V oder an 5.0V anschliesst, ist die Formel natürlich anders.

int input = analogRead(apin);

temperature = (5.0 * input * 100.0)/1024.0;

Serial.print( "Temperature: ");
Serial.print(temperature);
Serial.print("\n");
delay(1000);

Damit der Code da jetzt ein bisschen übersichtlich bleibt habe ich eine Funktion namens listenForClients() geschrieben. Ich denke aus den Kommentare sollte klar werden, was hier passiert:

void listenForClients() {

  // Initialize client
  Client client = server.available();

  if (client) {
    // Message for debugging
    // Serial.println("Got a client");

    boolean currentLineIsBlank = true;

    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        if (c == '\n' && currentLineIsBlank) {

          // Tell the client the receiving data is HTML
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          // This is the actual temperature value
	  // $deg; is the little round degree sign
          client.print("Temperature: ");
          client.print(temperature);
          client.print(" °C");

          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }

    // Give the web browser time to receive the data
    delay(1);

    // Close the connection:
    client.stop();
  }

Der Code ist überwiegend Copy-Pasta aus File/Examples/Ethernet/Webserver.

Hier gibts nochmal den Quelltext zum downloaden.

 

Fotos

(click to enlarge)

Foto Arduino Webserver LM35 Temperatursensor
Screenshot Arduino Webserver LM35 Temperatursensor

 

Links

flattr this!

24Feb/120

Standarddrucker abhaengig vom Standort setzen

Auf der Arbeit sind die PCs fortlaufend beschriftet und die letzten 3 Zeichen ist der Raum, also z.B. PC22-123 ist der 22. PC in Raum 123. Die Räume sind dabei IMMER dreistellig, d.h. in Raum 42 wäre der Raum 042. Natürlich könnte man auch über z.B. eine MySQL Datenbank eine Zugehörigkeit abfragen. Eine Abfrage könnte dann so aussehen(mehr oder minder Pseudo-Code):

SELECT RaumNr FROM Computer WHERE IP=$ip OR MAC = $mac;

Mit einem kleinen Perlskript im Autostart bekommt man seinen gewünschten Drucker anhand des Hostnames. Die entsprechende Perl Library für MySQL heisst Mysql(->use Mysql).

use Sys::Hostname;
$host = hostname;
chomp($host);
$raumnr=substr($host,length($host)-3,length($host)-1);
print "Host: " . $host . "\n";
print "RaumNr: " . $raumnr . "\n";

if ($raumnr == 123) {
  system('rundll32 printui.dll,PrintUIEntry /y /n "Drucker_Raum_123"');
}
elsif (...)
else {
   print "Computername nicht im richtigen Format";
}

hostname bekommt man vom System über sys::hostname. chomp() entfernt eventuelle Leerzeichen. Mittels substr() bekommt man einen Teilstring zurück, der von der Länge-3 bis Länge -1 geht, also genau die letzten 3 Buchstaben bzw. Zahlen. Hier hat man dann die Raumnummer. Anhand derer wird mit der rundll ein Standarddrucker gesetzt(/y) der in Anführungszeichen hinter /n steht. Damit sich die Anführungszeichen nicht in die Quere kommen, nimmt man für den system() Befehl die einstelligen Hochkommata.

flattr this!

9Feb/120

MAC-Adresse per Skript aus ifconfig

Soweit ich weiß, gibt es unter Linux keinen Befehl oder eine Datei in der die MAC-Adresse steht, nur ifconfig. Für die weitere Verwendung ist das natürlich unpraktisch und so habe ich hier eben ein bisschen was mit grep und regular expressions zusammengeskriptet/kopiert:

#!/bin/bash
ifconfig |grep $1 | grep -m 1 -Eo '[[:alnum:]][[:alnum:]](:[[:alnum:]][[:alnum:]]){5}'

Das am besten unter der Datei grepMacAdr speichern, noch schnell mit

chhmod +x  grepMacAdr

ausführtbar machen, dann erfolgt der Aufruf mit

./grepMacAdr eth0

eth0 ist hier das Netzwerkgerät. Wenn das bekannt ist kann auch direkt im Skript $1(=erster Parameter) durch die entsprechende Bezeichnung geändert werden.

Zur Erklärung: ifconfig ruft den Befehl auf, der alle Netzwerkgeräte samt Konfiguration ausgibt, von denen schneidet das Tool grep nur den Abschnitt heraus, der das übergebene Netzwerkgerät behandelt(bzw. die erste Zeile, da steht die MAC-Adresse im allgemeinen) und davon wiederrum wird mit einer Regular Expression(-E) dann nach dem Muster XX:XX:XX:XX:XX gesucht. Falls, was mit dem ersten grep falsch gelaufen ist, wird nur das erste ausgeben(-m 1). Ausgegeben wird dabei nur der Teil, der das Muster einhält, nicht die ganze Zeile(-o)

Ihr findet das Skript auch als fertige Datei hier.

flattr this!

14Sep/110

Arduino Uno mit Ubuntu 10.04 (Lucid Lynx)

Das Lucid Paket 0018 für Arduino von Ubuntu ist hoffnungslos veraltet, in dem Menü, in dem man sein Board auswählt, kommt der Uno noch garnicht vor. Allerdings kann man einfach die Maverik Pakete runterladen:

sudo apt-get install libjna-java

Dann die Pakete runterladen:

Die Pakete installieren:

sudo dpkg -i *.deb

Voila, jetzt erscheint auch der Uno in der Liste. btw, auch die ppa-Pakete bringen nichts, dort ist die neuste Version 0018. Mehr Infos im Arduino Playground.

flattr this!

12Sep/110

Standarddrucker von anderen Benutzern aendern

Drucker von anderen Usern zu ändern ist ja garnicht mal das Problem, man muss sich halt nur bei jedem User einzeln anmelden und den Drucker per Hand umstellen. Per Skript gibt es 2 Möglichkeiten: über rundll32 oder über die Registry.

1. rundll32-Methode (Danke an daedalus von administrator.de)

rundll32 printui.dll,PrintUIEntry /y /n "Druckername"

Einfach diesen Befehl in eine Textdatei schreiben und als .bat speichern. Das /n ist der Parameter für den Namen, der danach folgen muss, das /y heisst, dieser Drucker soll als Standarddrucker gesetzt werden. Das ist meiner Meinung nach die einfacherere Methode. Wenn der Druckername keine Leerzeichen enthält, können die Anführungszeichen auch weggelassen werden.

2. Registry-Methode (Danke an Micheal von Windows FAQ)

Da ist natürlich noch viel umständlicher ist in der Registry rumzupulen als den Drucker mal eben anzuklicken, kann man ein .reg-Skript schreiben dass den folgenden Inhalt hat:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Sofrware\Microsoft\Windows NT\CurrentVersion\Windows]"Device"="Standarddrucker,winspool,lpt01:"

Dabei steht der erste Wert für den Druckernamen, winspool ist die dll die für das Drucken zuständig ist und dann der Anschluss, wobei LPT: für Lokale und Ne: für Netzwerkdrucker und Software Drucker(z.B. PDF Generator) verwendet wird.

Um jetzt vom Adminstrator aus die Drucker zu ändern, kann man per runas die eben genannten Skripte starten, s. auch

runas /?

Aufrufe:

runas /user:username "C:\pfad\rundllskript.bat"

bzw.

runas /user:username "C:\pfad\registryskript.reg"

Ein Problem ergibt sich, wenn der User kein Passwort hat, da runas standardmässig, ausser bei Windows 2000, keine leeren Passwörter akzeptiert. Wenn man allerdings den Registry-Eintrag LimitBlankPasswordUse im Ordner HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa aus 0 ändert, ist auch das kein Problem mehr.(Tip aus der c't 1/06)

flattr this!

30Jul/110

Berechnen von Nullstellen in Matlab

Als Beispiel möchte ich hier die Funktion und ihre Ableitung benutzen:

Nullstellen mit Matlab: Funktion

  • a, b: Intervall
  • eta: Genauigkeit
  • format long: 15 Nachkommastellen

 

1. Bisektion (Wikipedia)

function [nullstelle,i]=bisektion(a,b)
  format long;
  eta = 0.00001;
  i=0;
  if(f(b)*f(a)<0)
    while(abs(b-a)>eta)
      if(f((a+b)/2)*f(a)>0)
        a=(a+b)/2;
      else
        b=(a+b)/2;
      end
      i=i+1;
    end
    nullstelle=(a+b)/2;
  end

function f_x=f(x)
  f_x=x.^6-x-1;

2. Newtown-Verfahren

function [nullstelle,i]=newton_verfahren(x)
  format long;
  eta=0.00001;
  diff=1;
  i=0;
  while(diff>eta)
    nullstelle = x;
    [f_x,fp_x]=f(x);
    x=x-f_x/fp_x;
    i=i+1;
    diff=abs(x-nullstelle);
  end
  nullstelle=x;

function [f_x,fp_x]=f(x)
  f_x  = x.^6-x-1;
  fp_x = 6*x.^5-1;

 

3. Sekanten-Verfahren

function [nullstelle,i]=sekanten_verfahren(a,b)
  format long;
  eta=0.00001;
  i=0;
  while(abs(b-a)>eta)
    nullstelle=b;
    b=b-f(b)*(b-a)/(f(b)-f(a));
    a=nullstelle;
    i=i+1;
  end
  nullstelle=(a+b)/2;

function f_x=f(x)
  f_x=x.^6-x-1;

4. Regular-Falsi

function [nullstelle,i]=regula_falsi(a,b)
  format long;
  eta=0.00001;
  i=0;
  diff=1;
  if(f(b)*f(a)<0)
    nullstelle = a;
    while(diff>eta)
      x=(a*f(b)-b*f(a))/(f(b)-f(a));
      if(f(x)<0)
        a=x;
      else
        b=x;
      end
      diff=abs(x-nullstelle);
      nullstelle = x;
      i=i+1;
    end
  end

function f_x=f(x)
  f_x=x.^6-x-1;

flattr this!

11Mai/110

Cronjobs von selbst wieder anstellen

Das Problem war ganz einfach, manuell dürfen einige wenige Berechtigte aus guten Gründen Cronjobs abstellen. Damit aber am nächsten Tag der Cronjob wieder läuft braucht man ein (nicht-abstellbaren) Cron Jobs, der alle anderen Cronjobs wieder anstellt. Glücklicherweise gibt es da die Schnittstelle Config::Crontab und so sind dies nur ein paar Zeilen(via CPAN bzw. man Config::Crontab):

#!/usr/bin/perl
use Config::Crontab;
my $ct = new Config::Crontab;
$ct->read; # alle crons auslesen a.k.a. crontab -l
$_->active(1) for $ct->select(-command_re => '/usr/local/bin/command'); # zeile vervielfachen fuer andere befehle
$ct->write; # alle crontabs schreiben, nicht vergessen!

Der gewünschte, nun wieder aktive Befehl ist /usr/local/bin/command.

flattr this!

15Jan/110

A few sed and awk scripts

Entfernt die erste Zeile und schreibt das Ergebnis in files.2.csv

sed '1,1d' file.csv >files.2.csv

Entfernt das Wort foobar aus der ganzen Datei und ersetzt es durch ein Leerzeichen.

sed 's/foobar/ /g'

Entfernt alle " aus der Datei. Problem dabei ist, dass Anführungszeichen normalerweise interpretiert werden. Mit einem Backslash wird sed gesagt, dass es sich um das Zeichen " handelt.

sed 's/\"/ /g'

-F, teilt awk mit, dass das Komma(,) das Trennzeichen ist und nicht z.B. ; oder :. Ähnlich wie bei C kann die Ausgabe formiert werden. Mit %Zahl wird die Breite für die Ausgabe festgelegt. Das s dahinter deutet einen String an. Das Minus der letzten Zahl bedeutet nicht etwa Invertierung sondern linksbündig, da standardmässig alles rechtsbündig ist. \n ist natürlich ein Absatz. Die $Zahl im hinteren Teil ist die Spalte aus der Datei file.csv

awk -F, '{ printf("%23s%10s\t%7s\t%10s\t %10s%10s%4s%-30s\n", $2, $8, $9, $10, $11, $14, $16, $22 )}' file.csv

Informationen findet man auf os4.org und Wikipedia zu sed bzw. awk

flattr this!

13Nov/104

27c3 Android App

Update: see below

Github: https://github.com/repat/27c3-Android-App

So this is my version of the 27c3 Android Fahrplan App. At the moment it only links to the fahrplan website, depending on which day/event you click. The advantage is, it's always uptodate;)

Please note the following:

  • I'm not a Java programmer, I just had a look at Android again after quite a while
  • This is a very alpha version
  • If I find some time, I'm gonna extend it to a real app
  • But I don't think so, so feel free to download the sourcecode and extend it yourself :-)
  • I really don't know why it's able to access the SD card and telephone status...don't worry about it;)(see comment)
  • It's quite late at night right now...:P

Download

Screenshots (click to enlarge)

android app 27c3 logo

android app 27c3 website

update:

  • added TabView for events and speakers
  • can't fix the Requirements(SD/Telephone status) because you need API Level 4 for targetSdkVersion. Otherwise all the people with Android <1.5 would not be able to use my app

flattr this!