21.12.17

Symfony mit composer unter Ubuntu 16.04 installieren

Nachdem ich composer über die apt Paketverwaltung installiert hatte, wollte ich im aktuellen Verzeichnis Symfony mittels composer installieren.

Es kam leider immer die Fehlermeldung

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - symfony/flex v1.0.9 requires composer-plugin-api ^1.1 -> no matching package found.
    - symfony/flex v1.0.8 requires composer-plugin-api ^1.1 -> no matching package found.

Die Suche über Google nach dieser Fehlermeldung brachte mich nicht gleich weiter. Aber möglicherweise war meine Version des composer zu alt.

 composer -V
Composer version @package_branch_alias_version@ (1.0.0-beta2) 2016-03-27 16:00:34

Ich habe dann diese Version wieder heruntergeworfen und das folgende Script von der composer Homepage heruntergeladen und ausgeführt.

#!/bin/sh

EXPECTED_SIGNATURE=$(wget -q -O - https://composer.github.io/installer.sig)
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_SIGNATURE=$(php -r "echo hash_file('SHA384', 'composer-setup.php');")

if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
then
    >&2 echo 'ERROR: Invalid installer signature'
    rm composer-setup.php
    exit 1
fi

php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php
exit $RESULT

Wenn alles geklappt hat, befindet sich in dem aktuellen Verzeichnis eine Datei

composer.phar

Diese kann man einfach als composer in das Verzeichnis /usr/local/bin/ kopieren und diese dann systemweit ausführen.

Check der Version:

 composer -V
Composer version 1.5.6 2017-12-18 12:09:18
Mit dieser Version ließ sich Symfony dann problemlos installieren.

8.12.17

MySQL - Schnellere Inserts

1. Je mehr Indizes, desto langsamer die Inserts!

Bei 20000 Einträgen dauert das Befüllen auf herkömmlichem Wege auf einem RPI3 ca. 140 Sekunden. Optimiert dauert es ca. 1.5 Sekunden!!!

Code, um Zeitaufwand für Inserts zu vergleichen.

function my_autoloader($class)
{
    include 'include/' . $class . '.php';
}
$cache=5000;
$usecache = true;
$inserts=10000;
spl_autoload_register('my_autoloader');
$db = new \PDO('mysql:dbname=newdb;host=localhost', 'DB', 'PASSWORD'');
for ($i = 1; $i <= $inserts; $i++)
{
    $data[] = ["id" => 1, "zip" => "30159", "name" => "Hannover", "citizens" => 50000];
}

$beginn = microtime(true);
$sql = 'INSERT IGNORE INTO testdaten (id, zip, name, citizens) VALUES ';
if ($usecache)
{
    $dbCache = new dbcache($db, $sql, $cache, true);

    foreach ($data as $entry)
    {
        $dbCache->add('(null,' . $db->quote($entry['zip']) . ',' . $db->quote($entry['name']) . ',' . ((int) $entry['citizens']) . ')');
    }
    $dbCache->flush();
}
 else
{
     $cache=0;
     foreach ($data as $entry)
     {
         $sql2= $sql . " ('null','" . $entry['zip'] . "','". $entry['name'] . "','" . $entry['citizens'] . "')";
         //echo "debug: $sql"; die;
         $db->query($sql2);
     }
}
$dauer = microtime(true) - $beginn;
echo "Verarbeitung des Skripts: $dauer Sek.<br>";
$sql = "SELECT count(*) from testdaten";
$result = $db->query($sql);
echo "Anzahl der Datensätze: " . $result->fetchColumn() . "<br>";
$db->query("TRUNCATE table testdaten");
$db->query("INSERT INTO performance (inserts, zeit, cache) VALUES"
        . "('$inserts','$dauer','$cache')");
DBCache Klasse, gefunden hier.

class dbcache
{
    public $lastQuery;

    private $db, $limit, $sql, $cache = [], $auto;

    /**
     * @param \PDO   $db
     * @param string $sqlPrefix
     * @param int    $limit
     * @param bool   $autoFlush
     */
    public function __construct(\PDO $db, $sqlPrefix, $limit, $autoFlush = false)
    {
        $this->db    = $db;
        $this->limit = $limit;
        $this->auto  = $autoFlush;
        $this->sql   = $sqlPrefix;
    }

    /**
     * @param string $query
     */
    public function add($query)
    {
        $this->cache[] = $query;

        if ($this->auto) {
            $this->softFlush();
        }
    }

    /**
     * Flush cache and query database.
     */
    public function flush()
    {
        if (empty($this->cache)) {
            return;
        }

        // save query for logging, if something goes wrong
        $this->lastQuery = $this->sql.implode(',', $this->cache);

        $this->db->query($this->lastQuery);
        $this->cache = [];
    }

    /**
     * Flush cache if limit is reached.
     */
    public function softFlush()
    {
        if (count($this->cache) >= $this->limit) {
            $this->flush();
        }
    }
}

20.9.17

Debian / Ubuntu / Apache - SSL auf die Schnelle

openssl genrsa -out /etc/ssl/private/apache.key 2048
 openssl req -new -x509 -key /etc/ssl/private/apache.key -days 365 -sha256 -out /etc/ssl/certs/apache.crt
 a2enmod ssl
 mcedit -d /etc/apache2/sites-available/default-ssl.conf
dort:         SSLCertificateFile /etc/ssl/certs/apache.crt
                 SSLCertificateKeyFile /etc/ssl/private/apache.key


a2ensite default-ssl.conf
service apache2 reload

17.9.17

Sonoff programmieren




Sonoff Pow
Sonoff Touch


Für das Board ohne Funkmodul gibt es hier eine gute Anleitung:









Der nötige Strom, der vom FTDI Modul geliefert wird, hat bei mir nicht ausgereicht.
Deshalb habe ich 3.3V und GND extern versorgt. GND muss dabei auch mit GND des FTDI Modules verbunden werden.



Ansonsten wie gehabt:
SONOFF                           FTDI
TX -> RX
RX -> TX
GND -> GND

Am besten noch einen Schalter zwischen 3.3V Netzteil und SONOFF.
In den Programmiermodus bringen. Taste am SONOFF drücken und gedrückt halten, Schalter umlegen, fertig.
In der Arduino IDE Generic ESP8266 auswählen.

Update:
Anscheinend gibt es bei den Modulen unterschiedlichen Chargen.
Nachdem ich fast verzweifelte, weil sich nach dem Flashen nichts tat, selbst bei einfachsten Sachen (Blink) und Serial.println, habe ich diesen Eintrag gefunden, der mir geholfen hat.

Unter Werkzeuge -> Flash Mode -> DOUT!!


Update: Im Quelltext von Tasmota  stand das auch schon drin. Wer zu faul zum Lesen ist, hat selber Schuld ;)


Wie schalte ich nun per curl? Wenn die Tasmota Firmware installiert ist, ganz einfach:


curl "[IP]/ay?o=0" - output=aus
curl "[IP]/ay?o=1" - output=an





Sonoff Power Schaltung:


GND
TxD
RxD
VCC


Binärdatei hochladen:
esptool.py --port COM4 write_flash 0x1000 d:\Downloads\tasmota8.bin
esptool.py --port COM10 write_flash 0x1000 d:\Downloads\tasmota8_2.bin
esptool.py --port COM10 write_flash 0x1000 d:\Downloads\tasmota-DE.bin
 esptool.py --port COM6 --baud 115200 write_flash -fs 1MB -fm dout 0x000000 d:\Downloads\tasmota-wifiman.bin

Sichern:
./esptool.py -p PORT -b 460800 read_flash 0 0x200000 flash_contents.bin

Oder die exe:

esptool.exe -cp COM3 -cb 115200 -bm dout -ca 0x00000 -cf d:\Downloads\tasmota.bin

warning: espcomm_sync failed
error: espcomm_open failed
error: espcomm_upload_mem failed

Welcher Port? chgport



26.7.17

VNC Server über SSH Tunnel

Tightvncserver installieren

sudo apt install tightvncserver

GGfs. Auflösung einstellen in der Datei

/etc/alternatives/vncserver
(als sudo)

Dort ist die Auflösung 1024x768 eingestellt unter $geometry


VNC Server starten

tightvncserver
New 'X' desktop is dhcp:1
Starting applications specified in /home/pi/.vnc/xstartup
Log file is /home/pi/.vnc/dhcp:1.log

Port dürfte sein 5901 ff.
Herausfinden lässt sich das mit netstat oder lsof

sudo lsof -i tcp | grep tight
Xtightvnc   528        pi    0u  IPv4 3834206      0t0  TCP *:x11-1 (LISTEN)
Xtightvnc   528        pi    3u  IPv4 3834208      0t0  TCP *:5901 (LISTEN)

Passwort setzen
 vncpasswd
Using password file /home/pi/.vnc/passwd
Password:
Warning: password truncated to the length of 8.
Verify:
Would you like to enter a view-only password (y/n)? n


Tunnel zu diesem Rechner einrichten

ssh -L 60000:[IP]:5901 user@computer

Danach kann z.B. mit dem portablen VNC Viewer eine Verbindung hergestellt werden mit

localhost:60000





14.7.17

Netdata deinstallieren

 killall netdata
 rm -Rf /usr/sbin/netdata
 rm -Rf /etc/netdata
 rm -Rf /usr/share/netdata
 rm -Rf /usr/libexec/netdata
 rm -Rf /var/cache/netdata
 rm -Rf /var/log/netdata
 rm -Rf /opt/netdata
 userdel netdata
 groupdel netdata

3.7.17

Telnet Brute Force

Ich weiß, so etwas wurde schon xmal geposted, trotzdem:

Ich wollte den (nicht dokumentierten) Telnet Zugang zu meiner Billig China Webcam bruteforcen.
Eine kurze Google-Suche ergab, dass das beliebte Tool nmap bereits ein entsprechendes Script beeinhaltet.

Aufruf:

nmap -p 23 --script telnet-brute --script-args userdb=user.txt,passdb=pw.txt 192.168.x.x.

User und Passwörter müssen in den entsprechenden Dateien zeilenweise vorhanden sein.

29.6.17

Ergebnisse aus NMAP in eine MySQL Datenbank schreiben

Es gibt bei Nmap die Möglichkeit die Ergebnisse von Netzwerkscans in eine XML-Datei zu schreiben. Die Weiterverarbeitung mit Linux-Bordmitteln ist jedoch nicht ganz trivial. Jedenfalls habe ich es mit xmlstartlet nicht so richtig hinbekommen.
Nmap wird z.B. gestartet mit

nmap -Pn 192.168.0178.0/24 -oX output/ZIELDATEI.xml

Mit einem Einzeiler, wie

xmlstarlet sel -t -m '/nmaprun/host' -v 'address[@addrtype="ipv4"]/@addr' -o ":" -v 'ports/port/@portid' -n /var/www/html/netzinfo/output/ZIELDATEI.xml

bekomme ich zwar alle Ports nacheinander angezeigt, doch die Zuordnung von IP Adressen zu den offenen Ports muss noch erfolgen.

Da ich das Ergebnis sowieso noch einmal durchgehen muss und alles in eine MySQL Datenbank eintragen will, habe ich mir das Ganze etwas vereinfacht und eine Sprache genommen, die ich etwas besser beherrsche: PHP.

Die Ausgabedatei habe ich testweise so eingeladen und ausgegeben:

$xml = file_get_contents("output/ZIELDATEI.xml");
$p = \xml_parser_create();
\xml_parse_into_struct($p, $xml, $data, $values);
\xml_parser_free($p);
echo "Index array <br><pre>";
print_r($values);
echo "data array <br><pre>";
print_r($data);
Ausgabe (auszugsweise):
260] => Array
        (
            [tag] => ADDRESS
            [type] => complete
            [level] => 3
            [attributes] => Array
                (
                    [ADDR] => 192.168.178.150
                    [ADDRTYPE] => ipv4
                )

        )

    [261] => Array
        (
            [tag] => HOST
            [value] => 

            [type] => cdata
            [level] => 2
        )

    [262] => Array
        (
            [tag] => ADDRESS
            [type] => complete
            [level] => 3
            [attributes] => Array
                (
                    [ADDR] => 74:75:48:A4:48:A8
                    [ADDRTYPE] => mac
                    [VENDOR] => Amazon Technologies
                )

        )
Auch hier ist es nicht so einfach, eine einwandfrei Zuordnung, von z.B. IP - Adressen zu offenen Ports und Mac-Adressen zu treffen.
Geholfen haben mir die Beispiele auf php.net und zwar die Funktion von efredericksen.

<?php class XmlElement {
  var
$name;
  var
$attributes;
  var
$content;
  var
$children;
};

function
xml_to_object($xml) {
 
$parser = xml_parser_create();
 
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
 
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
 
xml_parse_into_struct($parser, $xml, $tags);
 
xml_parser_free($parser);

 
$elements = array();  // the currently filling [child] XmlElement array
 
$stack = array();
  foreach (
$tags as $tag) {
   
$index = count($elements);
    if (
$tag['type'] == "complete" || $tag['type'] == "open") {
     
$elements[$index] = new XmlElement;
     
$elements[$index]->name = $tag['tag'];
     
$elements[$index]->attributes = $tag['attributes'];
     
$elements[$index]->content = $tag['value'];
      if (
$tag['type'] == "open") {  // push
       
$elements[$index]->children = array();
       
$stack[count($stack)] = &$elements;
       
$elements = &$elements[$index]->children;
      }
    }
    if (
$tag['type'] == "close") {  // pop
     
$elements = &$stack[count($stack) - 1];
      unset(
$stack[count($stack) - 1]);
    }
  }
  return
$elements[0];  // the single top-level element}
Die Ausgabe ist so, dass ich dann durch alle Ergebnisse der Nmap Ausgabe interieren kann.
Das PHP Script sieht so aus (quick and dirty):


$xml=file_get_contents("output/ZIELDATEI.xml");
$object = \xml_to_object($xml)->children;
// Gehe alle Objekte durch:
$anzahl = count($object);
for($i=0; $i<$anzahl; $i++)
{
    // IP Adresse
    $ip = $object[$i]->children[1]->attributes['addr'];
    if(strlen($ip)<1) continue;
    echo "Adresse: $ip<br>";
    // Rechnername
    $name=$object[$i]->children[3]->children[0]->attributes['name'];
    echo "Name: $name <br>";
    // MAC Adresse
    $mac=$object[$i]->children[2]->attributes['addr'];
    echo "MAC Adresse: $mac <br>";
    $vendor=$object[$i]->children[2]->attributes['vendor'];
    echo "Hersteller: $vendor <br>";
    // Offene Ports
    $anzahlports=count($object[$i]->children[4]->children);
    $port=""; $ports="";
    for($a=0;$a<$anzahlports; $a++)
    {
        $port=$object[$i]->children[4]->children[$a]->attributes['portid'];
        if(strlen($port)>0)
        {
            $ports.= $port . ";";
        }
    }
    echo "Offene Ports: $ports <br>";
}

Mit diesen Daten kann ich nun weiterarbeiten und sie z.B. in eine MySQL Datenbank schreiben.
Vielleicht hat jemand einfachere Lösungen??



28.6.17

isc-dhcp-server führende 0 fehlt

Ich hatte folgendes eingefügt in die dhcp.conf:

on commit {
        set clip = binary-to-ascii(10, 8, ".", leased-address);
       set clhw = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        log(concat("Commit: IP: ", clip, " Mac: ", clhw));
        execute("/home/pi/scripts/dash/dash_action", clip, clhw);
    }
}

Jedoch sorgt die Funktion binary-to-ascii dafür, dass mögliche führenden Nullen abgeschnitten werden. Das sorgt dann z.B. für eine solche Ausgabe:

e0:76:d0:60:3:fc
Abhilfe schafft folgendes:

         set clhw = concat (
            suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
            suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
            suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
            suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
            suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
            suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
            );

27.6.17

Mit Thunderbird Mails vom internen Netzwerk aufrufen

  • Postfix installieren
  • Dovecot installieren
  • SSH Tunnel einrichten mit Putty oder per Shell:
    ssh -L 54143:IP des Mailservers im Netz:143 -L 54025:IP des Mailservers im Netz:25 benutzer@netzwerk
  • In Thunderbird das Konto einrichten. Mailserver ist localhost mit Port 54143 bzw. 54025



26.6.17

Virtualbox: UUID der Festplatte ändern

Beim Kopieren (nicht über VBoxManage.exe) tritt das Problem auf, dass die UUID schon genutzt wird.

Abhilfe:
"c:\Program Files\Oracle\VirtualBox\VBoxManage.exe" internalcommands sethduuid "Pfad_Platte.vdi"

5.4.17

ESP8266 programmieren





Von: https://de.aliexpress.com/store/product/USB-to-ESP8266-Serial-Wireless-Wifi-Module-Developent-Board-8266-Wifi-Module/612195_32729552106.html




ESP8266 programmieren
3.3 V => 3.3V + CH_PD
GND => GND+GPIO0 (neben RX)
RX=> TX
TX=> RX
Zum Ausführen GPIO wieder von GND nehmen.


Von hier 


Interne LED: GPIO16
An:
digitalWrite(2, LOW);




Unter Datei - Voreinstellungen - Boardverwalter URL:
http://arduino.esp8266.com/stable/package_esp8266com_index.json

Werkzeuge - Board - Boardverwalter

 NodeMCU 1.0

Oder mit Wemos D1 mini.

Sketch:
/*
 *  This sketch sends a message to a TCP server
 *
 */

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

ESP8266WiFiMulti WiFiMulti;

void setup() {
    Serial.begin(115200);
    delay(10);

    // We start by connecting to a WiFi network
    WiFiMulti.addAP("SSID", "password");

    Serial.println();
    Serial.println();
    Serial.print("Wait for WiFi... ");

    while(WiFiMulti.run() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());

    delay(500);
}


void loop() {
    const uint16_t port = 80;
    const char * host = "192.168.178.4"; // ip or dns

   
   
    Serial.print("connecting to ");
    Serial.println(host);

    // Use WiFiClient class to create TCP connections
    WiFiClient client;

    if (!client.connect(host, port)) {
        Serial.println("connection failed");
        Serial.println("wait 5 sec...");
        delay(5000);
        return;
    }

    // This will send the request to the server
    client.print("Send this data to server");

    //read back one line from server
    String line = client.readStringUntil('\r');
    client.println(line);

    Serial.println("closing connection");
    client.stop();
   
    Serial.println("wait 5 sec...");
    delay(5000);
}


2.4.17

ESP 8266 DHT11 und Webserver

// SimpleDHT als Library einbinden
// Ggfs. vorher von der URL holen
// http://arduino.esp8266.com/stable/package_esp8266com_index.json
// DHT11
//GND-GND
//VCC - 3.3 V
//Data - Pin/GPIO 2 - D4

#include <SimpleDHT.h>

// Including the ESP8266 WiFi library
#include <ESP8266WiFi.h>

// Replace with your network details
const char* ssid = "SSID";
const char* password = "PASSWORD";

// Web Server on port 80
WiFiServer server(80);

// DHT Sensor
int pinDHT11 = 2;
// Initialize DHT sensor.
SimpleDHT11 dht11;

// Temporary variables
static char celsiusTemp[7];
static char fahrenheitTemp[7];
static char humidityTemp[7];

// only runs once on boot
void setup() {
  // Initializing serial port for debugging purposes
  Serial.begin(115200);
  delay(10);
 
  // Connecting to WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
 
  // Starting the web server
  server.begin();
  Serial.println("Web server running. Waiting for the ESP IP...");
  delay(10000);
 
  // Printing the ESP IP address
  Serial.println(WiFi.localIP());
}

// runs over and over again
void loop()
{
  // Listenning for new clients
  WiFiClient client = server.available();
    // read without samples.
  byte temperature = 0;
  byte humidity = 0;
    if (client)
  {
    if (dht11.read(pinDHT11, &temperature, &humidity, NULL))
    {
      Serial.print("Read DHT11 failed.");
      return;
    }
    String remote_ip = client.remoteIP().toString(); // IP Adresse des Client
    
    Serial.println("Neuer Zugriff von : " + remote_ip);
    // bolean to locate when the http request ends
    boolean blank_line = true;
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
                if (c == '\n' && blank_line)
        {
          // Computes temperature values in Celsius + Fahrenheit and Humidity
          // You can delete the following Serial.print's, it's just for debugging purposes
          Serial.print((int)temperature); Serial.print(" *C, ");
          Serial.print((int)humidity); Serial.println(" %");
        }
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println("Connection: close");
        client.println();
        // your actual web page that displays temperature and humidity
        client.println("<!DOCTYPE HTML>");
        client.println("<html>");
        client.println("<head></head><body><h1>ESP8266 - Temperature and Humidity</h1><h3>Temperature in Celsius: ");
        client.println((int)temperature);
        client.println("*F</h3><h3>Humidity: ");
        client.println((int)humidity);
        client.println("%</h3><h3>");
        client.println("<hr>" + remote_ip + "<br>");
        client.println("</body></html>");    
        break;
       
        if (c == '\n')
        {
          // when starts reading a new line
          blank_line = true;
        }
        else if (c != '\r')
        {
          // when finds a character on the current line
          blank_line = false;
        }
      }
    } 
    // closing the client connection
    delay(1);
    client.stop();
    Serial.println("Client disconnected.");
    
  }  
  }

28.2.17

Python - der Einstieg

Ich muss einige Stringmanipulationen vornehmen und einen UTC Timestamp umrechnen.

Da wäre zunächst einmal split, um einen String aufzusplitten

string="das ist ein test"
s=string.split() # splittet anhand des Leerzeichens (default)
for words in string:
       print words

Dann eine Art Substring

timestamp_orig="1389022616940757"
timestamp=int(timestamp_orig[0:10])
print(timestamp)
'1389022616'

Und diesen Timestamp dann schön ausgeben:
import date
import datetime
print(datetime.datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S'))


25.2.17

Arduino 433 MHZ Intertechno Funksteckdosen

http://www.rlobsiger.ch/jetzt-wirds-richtig-hell.html


Bibliothek importieren
Beispiel ausführen ShowReceivedCode


Ausgabe:
Addr 15821022 unit 1 off, period: 261us.
Addr 15821022 unit 2 off, period: 261us.
Addr 15821022 unit 0 on, period: 261us.
Addr 15821022 unit 1 on, period: 261us.
Addr 15821022 unit 1 off, period: 261us.
Addr 15821022 unit 0 off, period: 261us.
Addr 15821022 unit 2 off, period: 261us.


Ist nicht kompatibel zu den anderen Handsendern!

Billig Handsender aus China:

Diese Bibliothek einbinden. Beispiel ReceiveDemo_Advances und es gibt diese Ausgabe:

Decimal: 1393667 (24Bit) Binary: 000101010100010000000011 Tri-State: 0FFFF0F00001 PulseLength: 470 microseconds Protocol: 1
Raw data: 14596,468,1432,464,1432,464,1428,1436,484,472,1428,1448,476,484,1412,1452,468,488,1412,1444,476,480,1420,476,1420,480,1416,1444,476,480,1420,476,1420,476,1420,480,1420,472,1420,480,1420,476,1420,476,1420,1440,484,1440,484,



13.2.17

Mails von zu Hause verschicken über Postfix

Hier eine super Anleitung, mit der man Postfix so konfigurieren kann, dass er einen anderen Mailserver (z.B. den eigenen) als Relay mit SASL-Auth. nimmt.


Kurzform:
echo [mailrelay.domain.com] [username]:[password] > /etc/postfix/relay_password
postmap hash:/etc/postfix/relay_password
  

postfix/main.cf:
mynetworks_style = [host/subnet]

relayhost = [mailrelay.domain.com]
smtp_sasl_password_maps=hash:/etc/postfix/relay_password
smtp_sasl_auth_enable=yes
smtp_sasl_security_options = noanonymous

Bash - viele viele Nutzer anlegen

#!/bin/bash

GROUP="GRUPPE"
PASSWORD="Passwort"
HOME_BASE="/home/"
USER="Benutzername"

for ((i=1;i<25;i++))
do
  echo "Lege Benutzer ${USER}${i} an"
  /usr/sbin/useradd -g ${GROUP} -m -d "${HOME_BASE}${USER}${i}" "${USER}${i}"
echo "${USER}${i}":"${PASSWORD}${i}" | chpasswd
done.

11.2.17

Mit dem Raspberry den Arduino steuern

Hintergrund:
Ich habe ein Codeschloss installiert und mit einem Arduino verbunden.
Nun soll ein PI diesen ansteuern.
Nach etlichen Versuchen mit Python Scripten, nun erst einmal ein sehr einfaches Shell Script, mit dem ich das Menü des Arduino aufrufen kann.
Verbunden ist der Arduino ganz normal per USB mit dem Raspberry.

#!/bin/bash
SERIAL="/dev/ttyACM0"
while true
do
    read line
    echo $line > $SERIAL
    sleep 2
....
    cat $SERIAL
done
Ausgabe:

***** MENU ****
<enter> -> print this menu
  1     -> learn a code / paste csv-list of codes
  2     -> delete a code
  3     -> display all codes
  7     -> reset tamper flag & reboot
  8     -> save all codes to eeprom
  999   -> delete ALL codes in eeprom
Notes: Name entries max 9 characters.
       Action entries 1 for open, 0 for close.
To be continued...

4.2.17

Wiegand - next try - mit Arduino

Anhand dieser klasse Anleitung hatte ich endlich Erfolg.
Ich konnte den Code der RFIDs auslesen.
Zuvor war ich mit Pidoorman und dem Raspberry leider gescheitert.
Die Codes wurden nicht erkannt.

Nun aber mit dem Arduino.

Schaltung:

D0 Wiegand an D2 Arduino (D0 am DK-2872 => Blau)
D1 Wiegand an D3 Arduino (D1 => Gelb)
GND Wiegand and GND Arduino (GND => Schwarz)

Software von der o.a. Webseite.
HandleCodes.ino
/*
  Wiegand Door Controller
  Stefan Thesen, 2014
  Copyright: public domain -> do what you want
 
  For details visit http://blog.thesen.eu
 
  some code ideas / parts taken from Daniel Smith, www.pagemac.com
*/

#include <avr/eeprom.h>


////////////////////
// the setup routine
////////////////////
void setup()

  Serial.begin(9600);
  Serial.println(F("Wiegand Controller - S.T. 2014"));

  SetupCodeHandling();
  WiegandSetup();
  SetupUI();
 
  Serial.println(F(""));
  PrintMainMenu();
}


///////////////////////////////////////////
// main loop - handles reception & decoding
///////////////////////////////////////////
void loop()
{
  unsigned long ulFacilityCode, ulCardCode;
 
  // we have data?
  if (WiegandAvailable())
  {
    unsigned char i;
   
    Serial.print(F("Read "));
    Serial.print(WiegandBitCount());
    Serial.print(F(" bits. "));
   
    ulFacilityCode = WiegandFacilityCode();
    ulCardCode = WiegandCardCode();
    if (WiegandBitCount()!=0)
    {
      Serial.print(F("FacilityCode,CardCode = "));
      Serial.print(ulFacilityCode);
      Serial.print(F(","));
      Serial.println(ulCardCode);
      HandleCode(ulFacilityCode, ulCardCode);
    }
    else
    {
      Serial.println(F("Cannot decode. Unknown format."));
    }
   
    // clean up and get ready for the next card
    WiegandReset();
  }
}
UI.ino
/*
  User Interface Routines for Wiegand controller
  Stefan Thesen, 2014
  Copyright: public domain -> do what you want
*/

#include <avr/wdt.h>

//////////
// Globals
//////////

// note: Arduino String Objects eat (lots) of RAM dynamically and are not easy to predict
// so we do standard c 'strings', so that we can control memory
#define MAXSERBUFF 40                // max size for serial line in input
char sInBuffer[MAXSERBUFF];          // buffer for serial reading
int iMenuMode;                       // Mode flag for menu


void SetupUI()
{
  // init variables
  iMenuMode = 0;
  sInBuffer[0]=0;
}


/////////////////////////////////////////////////
// read serial input data and create input buffer
/////////////////////////////////////////////////
void serialEvent()
{
  char cc=0;
  if(Serial.available())
  {
    cc = Serial.read();
    if(cc==10||cc==13)
    {
       Serial.println(F(""));
       ProcessBuffer();
    }
    else
    {
      Serial.print(cc);
      int ipos = strlen(sInBuffer);
      if (ipos<MAXSERBUFF-1)
      {
        sInBuffer[ipos]=cc;
        sInBuffer[ipos+1]=0;
      }
    }
  }
}


//////////////////////////////////
// trigger actions by serial input
//////////////////////////////////
void ProcessBuffer()
{
  if (iMenuMode==0)
  {
    if (strcmp(sInBuffer,"1") == 0)
    {
      Serial.println(F("To add code/card enter: <Name,FacilityCode,CardCode,Action> as list or just <enter> to cancel"));
      Serial.print(F(">"));
      iMenuMode=1;
    }
    else if (strcmp(sInBuffer,"2") == 0)
    {
      Serial.println(F("To delete a code/card enter: Name"));
      Serial.print(F(">"));
      iMenuMode=2;
    }
    else if (strcmp(sInBuffer,"3") == 0)
    {
      // display all codes
      int ii;
      Serial.println(F("Codelist - Format: Name,FacilityCode,CardCode,Action"));
      for (ii=0;ii<iCodeListSize;ii++)
      {
        Serial.print(pCodeList[ii].sName);
        Serial.print(F(","));
        Serial.print(pCodeList[ii].ulFacilityCode);
        Serial.print(F(","));
        Serial.print(pCodeList[ii].ulCardCode);
        Serial.print(F(","));
        Serial.print(pCodeList[ii].bAction);
        Serial.println(F(""));
      }
      Serial.println(F("Codelist End."));
     
      iMenuMode=0;
    }
    else if (strcmp(sInBuffer,"7") == 0)
    {
      // reboot
      SetTamperFlag(false);
      asm volatile ("  jmp 0");
    }
    else if (strcmp(sInBuffer,"8") == 0)
    {
      // save to eeprom
      Serial.println(F("Saving to EEprom..."));
      SaveToEEProm();
      iMenuMode=0;
    }
    else if (strcmp(sInBuffer,"999") == 0)
    {
      // delete all codes
      iCodeListSize=0;
      Serial.println(F("Erasing EEprom..."));
      SaveToEEProm();
      iMenuMode=0;
    }
  }
  // ADD CODES AS CSV LIST
  else if (iMenuMode==1)
  {
    if (strlen(sInBuffer)==0)
    {
      iMenuMode=0;
    }
    else if (iCodeListSize<iMaxCodeList)
    {
      // find comma delimiters
      char *cFirstComma=NULL,*cSecondComma=NULL,*cThirdComma=NULL;  // set all to return code fail
      cFirstComma=strchr(sInBuffer,',');
      if (cFirstComma) cSecondComma=strchr(cFirstComma+1,',');
      if (cSecondComma) cThirdComma=strchr(cSecondComma+1,',');
      if (cFirstComma!=NULL && cSecondComma!=NULL && cThirdComma!=NULL)
      {
        pCodeList[iCodeListSize].ulFacilityCode = atol(cFirstComma+1);
        pCodeList[iCodeListSize].ulCardCode     = atol(cSecondComma+1);
        pCodeList[iCodeListSize].bAction        = atoi(cThirdComma+1);
       
        // name is max MAXNAMESIZE bytes incl termination char
        if ((cFirstComma-sInBuffer)>=MAXNAMESIZE) {cFirstComma=sInBuffer+MAXNAMESIZE-1;}
        memcpy((void*)pCodeList[iCodeListSize].sName,(void*)sInBuffer,cFirstComma-sInBuffer);
        pCodeList[iCodeListSize].sName[cFirstComma-sInBuffer]=0; // to be sure: term char
       
        // do not display status - otherwise arduino is too slow, when pasting a list
        //Serial.print(F("Entry added "));
        //Serial.print(pCodeList[iCodeListSize].sName);
        //Serial.println(F(". Next entry or hit Enter to exit."));
        //Serial.print(F(">"));
        iCodeListSize++;
      }
      else
      {
        Serial.println(F("Invalid entry! - Retry or hit Enter to exit."));
        Serial.print(F(">"));
      }
    }
    else
    {
      Serial.println(F("Maximum number of code entries reached! - Exiting."));
      iMenuMode=0;
    }   
  } 
  else if (iMenuMode==2)
  {
    // delete a code
    int ii=0;
    bool bFound=false;
    while (ii<iCodeListSize && !bFound)
    {
      if (strncmp(sInBuffer,pCodeList[ii].sName,MAXNAMESIZE)==0) {bFound=true;}
      else { ii++; }
    }
    if (bFound)
    {
      int ikill=ii;
      iCodeListSize--;
      for(ii=ikill;ii<iCodeListSize;ii++)
      {
        memcpy((void*)&pCodeList[ii],(void*)&pCodeList[ii+1],sizeof(CODELIST));
      }
      Serial.println(F("Entry removed."));
    }
    else
    {
      Serial.println(F("Entry not found!"));
    }
    iMenuMode=0;
  }
 
  // prepare for next inputs
  sInBuffer[0]=0;
  if (iMenuMode==0) {PrintMainMenu();}
}


///////////////////////
// prints the main menu
///////////////////////
void PrintMainMenu()
{
  Serial.println(F("***** MENU ****"));
  Serial.println(F("<enter> -> print this menu"));
  Serial.println(F("  1     -> learn a code / paste csv-list of codes"));
  Serial.println(F("  2     -> delete a code"));
  Serial.println(F("  3     -> display all codes"));
  Serial.println(F("  7     -> reset tamper flag & reboot"));
  Serial.println(F("  8     -> save all codes to eeprom"));
  Serial.println(F("  999   -> delete ALL codes in eeprom"));
  Serial.print  (F("Notes: Name entries max "));
  Serial.print  (MAXNAMESIZE-1);
  Serial.println(F(" characters."));
  Serial.println(F("       Action entries 1 for open, 0 for close."));
  Serial.println(F(""));
  Serial.print  (F(">"));
}
Wiegand_Controller.ino
/*
  Wiegand Door Controller
  Stefan Thesen, 2014
  Copyright: public domain -> do what you want
 
  For details visit http://blog.thesen.eu
 
  some code ideas / parts taken from Daniel Smith, www.pagemac.com
*/

#include <avr/eeprom.h>


////////////////////
// the setup routine
////////////////////
void setup()

  Serial.begin(9600);
  Serial.println(F("Wiegand Controller - S.T. 2014"));

  SetupCodeHandling();
  WiegandSetup();
  SetupUI();
 
  Serial.println(F(""));
  PrintMainMenu();
}


///////////////////////////////////////////
// main loop - handles reception & decoding
///////////////////////////////////////////
void loop()
{
  unsigned long ulFacilityCode, ulCardCode;
 
  // we have data?
  if (WiegandAvailable())
  {
    unsigned char i;
   
    Serial.print(F("Read "));
    Serial.print(WiegandBitCount());
    Serial.print(F(" bits. "));
   
    ulFacilityCode = WiegandFacilityCode();
    ulCardCode = WiegandCardCode();
    if (WiegandBitCount()!=0)
    {
      Serial.print(F("FacilityCode,CardCode = "));
      Serial.print(ulFacilityCode);
      Serial.print(F(","));
      Serial.println(ulCardCode);
      HandleCode(ulFacilityCode, ulCardCode);
    }
    else
    {
      Serial.println(F("Cannot decode. Unknown format."));
    }
   
    // clean up and get ready for the next card
    WiegandReset();
  }
}

3.2.17

Makibes 10.1 Zoll Display am Raspberry

Nachdem ich mir das Makibes Display bei Amazon gekauft hatte, habe ich versucht ihn an dem Raspberry zu betreiben.
Zu meiner Schande muss ich gestehen, dass ich 3/4 der Zeit damit verbracht hatte, das Flachbandkabel, was von der Schaltplatine kommt, mit dem LCD-Schirm zu verbinden.
Das Problem lag daran, dass ich diese schwarzen "Nupsis", die das Flachbandkabel halten sollen, ganz herausgezogen hatte.
Stattdessen muss man die mit leichtem Druck nach oben biegen, das Kabel einlegen und wieder zurück in die Ausgangsposition bringen.

Wenn das geschafft ist, kann man das Display über HDMI mit dem RPI verbinden.
Dann noch eine USB-Verbindung vom RPI zum Display und die config.txt anpassen.

Unter /boot/config.txt eintragen:

max_usb_current=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt 1024 600 60 6 0 0 0

Und darauf achten, dass als "Source" HDMI gewählt ist!! (auch damit hatte ich 30 Minuten verschwendet)

Hier die Herstellerseite, die aber nicht sehr viel hergibt.

12.1.17

Postfixadmin

apt-get install postfixadmin

Fix:
1. /etc/postfixadmin/dbconfig.inc.php
$dbtype=mysqli

2. Fehler:bei https://gehrdener.de/postfixadmin/setup.php?debug=1
DEBUG INFORMATION:
Invalid query: Invalid default value for 'created'


Fix:
Strict Mode off:

Erstelle
/etc/mysql/conf.d/disable_strict_mode.cnf
 
Inhalt:
sql_mode=IGNORE_SPACE,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
 
service mysql restart
 
 
Alias definieren in /etc/main.cf
 virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_alias_maps.cf

Inhalt:
hosts = localhost
user = [DBUSER]
password = [PASSWORD]
dbname = [DBNAME]
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
 
Virtuelle Domänen
Main.cf: 
virtual_alias_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf

 
In der mysql-virtual_domains.cf  
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'

9.1.17

Sync auf NAS@home

Aufbau:

@home ist ein PI per SSH über einen bestimmten Port erreichbar - Portweiterleitung über Fritzbox.

Ziel:
Sync von Daten, die unterwegs angefallen sind, auf das im Heimnetzwerk erreichbare NAS.

1.Remote Tunnel einrichten

ssh -p [PORT des PI] -L 60000:[IP des NAS]:22 pi@home

2. Verzeichnis per sshfs einbinden
sshfs -p 60000 root@localhost:[PFAD auf dem NAS]/ /[MOUNTPOINT]


3. Syncen wie gehabt :)


Openhab und Ecoflow Max - API Anbindung

 Ich wollte die neu erworbene Powerstation in Openhab einbinden, um den aktuellen Status (Ladestand etc.) über Openhab auswerten zu können. ...