SBS2011 Domäne durch UCS ergänzen (und hoffentlich irgendwann ablösen)

Ich darf einen SBS2011 langsam durch UCS ablösen. Das Teil ist überfällig, also einfach mal frisch drauf los gearbeitet.
UCS installiert, Wizard gestartet und Active-Directory beitreten angeklickt. Und dann gings auch schon los…
Was ich jetzt (nach vielen Fehlversuchen) weiss:
Man sollte jeden neuen UCS (also auch weitere UCS die man dann mit UCS beitreten (nicht wieder AD!) hinzufügen kann, gleich mal vorher im DNS am SBS2011 anlegen.

Wenn man den UCS Master dann installiert hat, gleich mal die nächste Falle:
Den Domain-Admin User muss man in die UCS Gruppe „DC Backup Hosts“ geben, fragt mich nicht warum.
Dann hab ich gleich weitergebaut und wie von Univention vorgeschlagen einen Backup DC installiert. Achtung, kein Beitreten zu AD sondern UCS im Install. Klappt.
Einen Slave für den neuen Mailserver installiert.
2 Slaves in Zweigstellen (andere Netzwerke mit VPN angeknüpft) installiert als Vorort-Authentifizierung. Achtung: zusätzlich zu den in der Univention vermerkten Ports braucht man auch von Remote die Ports 139 und 445 um sich im AD während der Installation anzumelden.

Das waren erstmal alle Domain Controller.

Ab zur Software:
Am UCS Master habe ich installiert: Nagios und den Software Monitor um das Konstrukt zu überwachen. Nagios muss auf allen Rechnern installiert werden. Ob das beim Software Monitor auch so ist muss ich erst testen. Ergebnis: Nein, der Software Monitor wird nur einmal zentral installiert. Achtung, aktualisiert werden die Daten immer nur bei einem Update / Software install oder ähnlichem.

Jetzt mal nachdenken wie man das alles sichern kann. Während ich das weiter überlege, mal sehen wie man Exchange ersetzen kann.
Kopano getestet, funktioniert soweit, mit Outlook und auch Handy Sync. Aber kann keine öffentlichen Ordner direkt sondern nur über Umwege und umständlich (die in meinem Fall als Ablage verwendet werden). Auch Kalender freigeben klappt nicht.

Mal schauen was OX kann. OX kann ich gleich nicht mal die GUI als Benutzer verwenden. Noch mal Kopano ansehen…

Kopano ist scheinbar die bessere Option von den 2 (zumindest für mich hier).
Vieles wird aber über die Webapp eingestellt, zB die Freigabe eines Kalenders. Diese Freigabe kann man dann mit der KOE (addon zu Outlook) wieder laden und als verknüpften Ordner in die eigene Struktur nehmen.

Regenwassertank Füllstand messen mit Raspberry Pi; Version 2020

Aufgrund der vielen Besucher des Themas, hier neu zusammengefasst, das komplette Thema!

Wer die Entstehung und die Rückschläge sucht, findet die alten Beiträge im Archiv.

Hardware:

Raspberry Pi
DYP-ME007Y

 

Software:

Am Ende wurde es: python und mysql

Vorwort zum DYP-ME007Y: hier gibt es wohl verschiedene Versionen, die beste Erklärung dazu habe ich hier gefunden: JSN-SR04T-2.0.pdf

Ich verwende jetzt die Variante mit 120kOhm Widerstand.

Achtung: Ich hatte versucht, den Raspberry und die Platine des Sensors im Keller zu lassen und mit einem langen Kabel den eigentlichen Sensor angeschlossen. Die Signale brechen aber zu oft ab als dass das praktikabel wäre. Das bedeutet, die Platine muss mit raus zum Tank. Damit die Feuchtigkeit die Platine nicht vernichtet, bitte unbedingt gut einpacken, verkleben oder ähnliches!

Mein Tank ist ein liegender Zylinder, was bedeutet, dass 10 cm Unterschied in der Mitte im Wasserstand viel mehr Volumen hat als der selbe Unterschied ganz oben oder ganz unten.

Also mal auf die Suche gemacht nach einer verwendbar einfachen Formel.
Der zweite Treffer in der Online-Suche war

Methode 3 klingt ja schon gut. Erst mal zur Kontrolle und zum Verständnis ein Beispiel gerechnet, klappt.

Raspbian ISO auf die SD-Karte, anstarten.

sudo raspi-config

Passwort und Locale ändern nach Bedarf. SSH aktivieren und Serial Zugriff deaktivieren (das kommt im Hauptteil noch einmal vor).

Danach LAMP installieren, aber ohne den FTP Teil:

https://pchelp.ricmedia.com/setup-lamp-server-raspberry-pi-3-complete-diy-guide/3/

Ftp braucht niemand, sftp funktioniert und SSH haben wir ja schon.

mysql_secure_installation

CREATE USER ‚root2’@’localhost‘ IDENTIFIED BY ‚NewPassword‘; #Hier ein eigenes Passwort vergeben!

GRANT ALL PRIVILEGES ON * . * to ‚root2’@’localhost‘ WITH GRANT OPTION;

Datenbank regenwasser anlegen, Benutzer regenwasseruser, Rechte vergeben, Tabelle Volume mit3 Spalten: id als INT mit auto_increment, datetime mit Format datetime und volume als INT.

apt-get install python-mysqldb
Auch wichtig: apt-get install python-serial
Disable the login shell on the serial port in the interfacing options of „sudo raspi-config“, and reboot. For B+ that may be all that is required.
Endlich das Geheimnis um das 0X55 Kommando mit viel probieren gelöst. Und dann noch mehr probiert, denn nirgends ist dokumentiert, dass man noch einmal ein Kommando senden muss um die Platine wieder zu deaktivieren.
Dann einen Codeblock gebaut, der Werte die zu weit außer dem Mittelwert sind verwirft und noch einmal einen neuen Mittelwert bildet.
Dann ein Codeblock der die komplette Messreihe verwirft wenn das Ergebnis nicht plausiebel ist, also außerhalb der Größe des Tanks.
Dann ein Code der vom Abstand umrechnet auf die Füllmenge des Tanks. Mein Tank sieht wie eine liegende Tonne aus, also sind Füllstand und Volumen nicht linear.
Dann das Ergebnis in eine Datenbank schreiben. Endlich fertig.
Und hier der komplette Code:
</pre>

#!/usr/bin/python
# coding=utf8
import time
import math
import sys
import RPi.GPIO as GPIO

#################### select mode ######################
# mode 1 = analog (R27 empty)
# mode 2 = serial, running continuous (R27 = 47kOhm)
# mode 3 = serial with trigger from script (R27 = 120kOhm)
mode=3 

#################### Tank settings ####################
voll=70 # 70 cm von Sensor bis Wasseroberfläche = voll
leer=230 # 230 cm von Sensor bis Wasseroberfläche= leer
laenge=230 #230 cm Länge des Tanks
radius=90 #90 Radius Tank
korr= 0 # 20 wird zur Entfernung addiert
echo_time = 2 # delay between measurements in seconds ### make sure no echo is left
allowed_dev = 0.1 # filter out wrong measurements

#################### serial settings ####################
if (mode == 3) or (mode == 2):
	import serial
	#seriellen Port einstellen
	ser = serial.Serial("/dev/ttyAMA0", baudrate=9600) #, timeout=3.0
	ser = serial.Serial(
               port='/dev/ttyAMA0',
               baudrate = 9600,
               parity=serial.PARITY_NONE,
               stopbits=serial.STOPBITS_ONE,
               bytesize=serial.EIGHTBITS,
               timeout=1
           )
#################### analog settings ####################
elif (mode == 1):
	GPIO.setmode(GPIO.BOARD)
	trig=13
	echo=15
	GPIO.setup(echo,GPIO.IN)
	GPIO.setup(trig,GPIO.OUT)
else:
	print "Mode falsch."
	print >> sys.stderr, "Mode falsch."
	GPIO.cleanup()
	sys.exit(1)

###### main ###############
entfernung=0
gesamt=0
entf_array = {}
for i in range(0,10):
	if (mode == 1): ### analog
		GPIO.output(trig,True)
		time.sleep(0.00001)
		GPIO.output(trig,False)
		j = 0
		while GPIO.input(echo) == 0:
			pass
		start=time.time();
		while GPIO.input(echo) == 1:
			pass
		ende = time.time();
		entfernung=(((ende - start) * 34300) / 2)+korr
	elif (mode == 2): ### serial cont.
		ser.flushInput()
		#import pdb
		#pdb.set_trace()
		#ser.write(bytes([0x55]))
		#startbyte = ord(ser.read(1))
		startbyte = 1
		while startbyte != 255:
			read = ser.read(1)
			print read
			if len(read) == 0:
				continue
			else:
				startbyte = ord(read)
			hbyte = ord(ser.read(1))
			lbyte = ord(ser.read(1))
			sbyte = ord(ser.read(1))
		entfernung = (hbyte * 256 + lbyte)/10 + korr
		summe = startbyte + hbyte + lbyte
		summe = summe - (int(summe/256) * 256)
		if summe != sbyte:
			entfernung = 0
		print(startbyte, hbyte, lbyte, sbyte, entfernung)
	elif (mode == 3): ### serial standby
		ser.flushInput()
		ser.write(chr(0X55))
		#startbyte = ord(ser.read(1))
		#import pdb
		#pdb.set_trace()
		startbyte = None
		while startbyte != 255:
			read = ser.read(1)
			if len(read) == 0:
				ser.flushInput()
				continue
			else:
				startbyte = ord(read)
				hbyte = ord(ser.read(1))
				lbyte = ord(ser.read(1))
				sbyte = ord(ser.read(1))
				ser.flushInput()
			ser.write(chr(0X55))
		ser.write(chr(0X55))
		entfernung = (hbyte * 256 + lbyte)/10 + korr
		summe = startbyte + hbyte + lbyte
		summe = summe - (int(summe/256) * 256)
		if summe != sbyte:
			entfernung = 0
		#print (i)
		#print(startbyte, hbyte, lbyte, sbyte, entfernung)
	print entfernung
	entf_array[i] = entfernung
	gesamt=gesamt+entfernung
	time.sleep(echo_time)
mittelwert=gesamt/(i+1)

##### filter mismatching measurements
i = 0
gesamt = 0
for entf in entf_array:
	if entf_array[entf] < mittelwert*(1+allowed_dev) and entf_array[entf] > mittelwert*(1-allowed_dev):
		gesamt=gesamt+entf_array[entf]
		i=i+1
mittelwert=gesamt/(i)
##### discard if median is outside full or empty
if (mittelwert < voll or mittelwert > leer):
	print "Messung ausserhalb Bereich: " + str(mittelwert)
	print >> sys.stderr, "Messung ausserhalb Bereich: " + str(mittelwert)
	mittelwert = None
	volumen = None
	#if (mode == 1):
	#	GPIO.cleanup()
	#sys.exit(1)
else:
	##### convert distance to round tank volume
	print "Entfernung: ",  mittelwert, " cm"
	hoehe = (leer - mittelwert)
	acosval = (radius - hoehe)/float(radius) # float needed else python rounds to int
	alpha = 2*math.acos(acosval)
	volumen = int(round(laenge * radius*radius/2*(alpha -math.sin(alpha))))
	check = False
	if check:
		print "leer: ",  leer, " cm"
		print "radius: ",  radius, " cm"
		print "laenge: ",  laenge, " cm"
		print "hoehe: ",  hoehe, " cm"
		print "acosval: ",  acosval, ""
		print "alpha: ",  alpha, " rad"
		print "Volumen: ", volumen, " cm³"
	print "Volumen: ", volumen/1000, " Liter"
	print "- - - - - - - - - - - - - - - - - - - - - "
#f1=open('/var/scripts/regentank_check/entfernung.txt','w')
#print >> f1, '%d' % (mittelwert)
#f1.close()

#f2=open('/var/scripts/regentank_check/volumen.txt','w')
#print >> f2, '%d' %(volumen)
#f2.close()

#f1l=open('/var/scripts/regentank_check/entfernung.txt','r')
#f2l=open('/var/scripts/regentank_check/volumen.txt','r')

#serverftp = ftplib.FTP('ftp.server.de', 'user', 'pass')
#serverftp.storbinary('Stor entfernung.txt', f1l)
#serverftp.storbinary('Stor volumen.txt', f2l)
#serverftp.quit()

import MySQLdb
db = MySQLdb.connect(host="localhost",    # your host, usually localhost
                     user="regenwasseruser",         # your username
                     passwd="password",  # your password
                     db="regenwasser")        # name of the data base

# you must create a Cursor object. It will let
#  you execute all the queries you need
cur = db.cursor()

# Use all the SQL you like
if volumen:
	vol_string = str(int(round(volumen/1000,0)))
else:
	vol_string = "Null"
cur.execute("INSERT INTO volumen (`datetime`,`volume`) VALUES (now()," + vol_string + ")")

db.commit()
db.close()

#### clean up after using GPIO mode
if (mode == 1):
	GPIO.cleanup()
<pre>

Und zu guter letzt, noch meine Skizzen von der Verkabelung, für Modus 1, 2 und 3:

Modus 1, analog, kein Widerstand:

Modus 2, seriell Dauer, 47kOhm Widerstand:

Modus 3, seriell Standby, 120kOhm Widerstand:

 

Und noch eine Warnung: ich hatte einen Schlauch quer durch den Tank liegen von der Wasserpumpe. Der Sensor hat, als der Wassertand fiel, den Schlauch erfasst. Unbedingt darauf achten, dass die Richtung in die der Sensor misst auch wirklich frei ist.

Ich lasse das script jetzt einmal pro Tag per crontab laufen.

Hier der Code für eine Anzeige des Füllstands.

Wir lesen den letzten Wert aus der Datenbank aus.

 

 <?php #ini_set('display_errors', 1); #ini_set('display_startup_errors', 1); #error_reporting(E_ALL); $servername = "localhost"; $username = "regenwasseruser"; $password = "Passwort_Hier"; $dbname = "regenwasser"; $max_volume = 5853; // Create connection $conn = new mysqli($servername, $username, $password, $dbname); // Check connection if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

$sql = "SELECT volume, datetime FROM volumen order by id DESC limit 1";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
$volume = $row["volume"];
$datetime = substr($row["datetime"],0,-3);
#$datetime = strtotime($row["datetime"]);
$datetime = date("d.m.Y H:i", strtotime($row["datetime"]));
$percent = round($volume / $max_volume * 100 ,2);
//if ($result->num_rows > 0) {
    // output data of each row
 //   while($row = $result->fetch_assoc()) {
 //       echo "id: " . $row["id"]. " - Name: " . $row["firstname"]. " " . $row["lastname"]. "
";
 //   }
//} else {
 //   echo "0 results";
//}
$conn->close();
?> 
<label for="fuel">Regenwassertank: </label>

<meter id="fuel" name="fuel"
       min="0" max="<?php echo $max_volume?>"
       low="2000" high="<?php echo $max_volume?>" optimum="<?php echo $max_volume?>"
       value="<?php print "$volume";?>">
    </meter>

    <?php print "$datetime <b>$percent</b>"?>%

Automatisch pdfs ausdrucken Ubuntu Server

Aufbauend auf dem letzten Beitrag, jetzt die Steigerung.

Ich will dass pdfs einmal in Farbe und einmal in schwarzweiss ausgedruckt werden, wenn man sie in einem bestimmten Verzeichnis ablegt. Und dann gelöscht werden.

Scheint ja einfach. https://unix.stackexchange.com/questions/72779/script-to-check-a-folder-print-the-files-then-delete-those-files

Also den Drucker ein zweites Mal in CUPS installieren, mit Einstellung schwarzweiß.

Das hier schaut noch besser aus:

https://askubuntu.com/questions/675195/how-to-print-pdf-files-automatically-from-a-directory

Super, wer inoticoming stoppen will, sucht sicher die PID

ps -p $(find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print 2> /dev/null | sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1/')

Leicht abgeändert vom Original, weil lpr bei mir nicht arbeiten wollte:

lp -d Brother9140sw „$2/$1“ && rm „$2/$1“

 

ABER: inicoming läuft bei mir nach einem reboot nicht mehr.

Nächster Versuch: https://unix.stackexchange.com/questions/16043/automatically-rename-files-when-they-are-placed-in-a-specific-directory

apt-get install incron

nano /etc/incron.allow

root eintragen

jetzt klappts!

Brother MFC-9140CDN an Ubuntu Server CUPS

Erst mal cups installiert, dann die Web Gui installiert.

Wer Zugriff verweigert bekommt, sollte sich erst einmal nur selbst freigeben, mit

Allow from 10.10.10.5

im richtigen Bereich, vermutlich / und /admin.

Evtl. Firewall Port freigeben.

Dann hat bei mir apparmor Probleme gemacht, Internet sagt:

apt-get install apparmor-utils

aa-complain cupsd

Sooo….

Drucker suchen funktionierte vermutlich wegen unterschiedlichem Subnet nicht, also Drucker hinzufügen geklickt.

Internet Printing Protocol (http)

http://IP_Adresse_Drucker:631

Namen vergeben.

Treiber: crap

also erst mal https://github.com/pdewacht/brlaser#user-content-brlaser-brother-laser-printer-driver gelesen und mit apt-get install printer-driver-brlaser

ein paar Treiber installiert.

Hier https://wiki.gentoo.org/wiki/Brother_networked_printer#net-print.2Fbrlaser

wird der Drucker als funktionsfähig beschrieben, ich weiss nur nicht welchen Treiber ich nehmen soll.

Also bei brother runtergeladen die .deb (english).

https://support.brother.com/g/b/downloadhowto.aspx?c=at&lang=de&prod=mfc9140cdn_eu_as_cn&os=128&dlid=dlf100407_000&flang=4&type3=561

Beim Install wird der Drucker per USB eingerichtet, den kann man gleich wieder löschen wenn man den Drucker im Netzwerk hat.

Und siehe da, in der Treiberauswahl kann man den 9140 jetzt auswählen.

Testseite: erfolgreich!

Prestashop Unterkategorien oberhalb der Produkte anzeigen

ACHTUNG: MACHT DAS BITTE (anders als im Original angegeben) in einem Child Theme!

Dazu gibt es schon was: https://mypresta.eu/prestashop-17/display-available-subcategories.html

aber ich finde, 3 Elemente pro Zeile sind deutlich übersichtlicher.

Deshalb das css angepasst:


#subcategories ul {
margin: 0 0 0 -20px;
-moz-column-count: 3;
-webkit-column-count: 3;
column-count: 3;
-webkit-column-break-inside: avoid; /* Chrome, Safari */
page-break-inside: avoid; /* Theoretically FF 20+ */
break-inside: avoid-column; /* IE 11 */
display:table; /* Actually FF 20+ */
}

#subcategories ul li {
float: left;
width: 145px;
margin: 0 0 13px 33px;
text-align: center;
height: 202px;
break-inside: avoid-column;
}

 

Prestashop Wochentage abgekürzt

Prestashop 1.7 bleibt für mich nervig.

Wer zum Beispiel Übersetzungen sucht, sollte schon mal viel Geduld mitbringen und gute Nerven. Teilweise hilft nur der Blick in den Sourcecode um zu sehen, in welchem Bereich eine Übersetzung zu finden ist.

Und dann gibt es noch Sachen, die einfach unpraktisch gelöst sind.

Zum Beispiel die Abkürzungen der Wochentage wenn man Öffnungszeiten anzeigen will. Prestashop zeigt an: Mon., Die., Mit., Don., Fre., Sam., Son.

Spätestens bei „Fre.“ merkt man, das ist auf Deutsch einfach Quatsch.

Wer nun die Übersetzung suchen beginnt, wird länger suchen, denn die Wochentage sind nur in der Volltext-Version übersetzt. Monday = Montag usw.

Die Abkürzungen werden (siehe Sourcecode) direkt im Template aus den eigentlichen Wochentagen gezogen. 3 Zeichen plus „.“ ergibt Abkürzung.

Gut für Englisch, für Deutsch weniger.

Wer das wenigstens aufhübschen will (und die Änderung für alle Sprachen in Kauf nimmt) gräbt in das Template.

\themes\classic\templates\cms\stores.tpl

und ändert dort folgende Zeile


<th>{$day.day|truncate:4:'.'}</th>

um auf


<th>{$day.day|truncate:3:'.'}</th>

Damit steht nicht mehr „Mon.“ sondern „Mo.“

BESSER NOCH: kopiert euch die Datei in euer Child-Theme und macht dort die Änderung. Damit richtig vererbt wird oben in der Datei das bestehende extend ersetzen durch {extends file=’parent:cms/stores.tpl‘}.

freepbx AMI port Zugriff

Für alle die das so lange suchen wie ich, oder sich so wie ich wundern warum der Zugriff auf AMI nicht funktioniert.

Der AMI port 5038 ist in der freepbx nicht als Service angführt.

Das macht natürlich in der Firewall Probleme, wenn man korrekterweise die zugreifenden IPs als „Local“ definiert.

Daher in der Firewall in den Benutzerdefinierten Services den Port 5038 eintragen. Dann lässt sich der AMI Zugriff über die Firewall regulär steuern.

lets-chat in freepbx absichern mit tls

Dass das nicht Standard ist, stört mich total.

Also erst mal in /var/www/html/admin/modules/xmpp/node/node_modules/lets-chat/settings.yml den Teil für TLS eingefügt.

xmpp:
  enable: true
  port: 5222
  domain: 0.0.0.0
  roomCreation: true
  debug:
    handled: true
    unhandled: true
  tls:
    enable: true
    key: /etc/asterisk/keys/default.key
    cert: /etc/asterisk/keys/default.crt

Und schon funktioniert freepbx lets-chat mit XMPP mit TLS.

freepbx mit BLF inkl. DND und Unavailable

Nach einer längeren Testphase von 3cx, stellte sich heraus, dass 3CX bei allen Themen rund um Presence nur am eigenen Sofphone richtig funktioniert. Völlig uninteressant wenn man ein echtes VOIP-Telefon hat, dass die Funktionen ordnetlich abbilden könnte.

freepbx ist da out-of-the-box wesentlich besser zu steuern.

DND war relativ einfach umzusetzen, da die hints schon vorhanden waren. Ich habe aber einen anderen Status verwendet, um echtes Läuten des Telefons und DND zu unterscheiden.

nano /etc/asterisk/extensions_override_freepbx.conf


[app-dnd-on]
include => app-dnd-on-custom
exten => *78,1,Macro(user-callerid,)
exten => *78,n,Set(CONNECTEDLINE(name-charset,i)=utf8)
exten => *78,n,Set(CONNECTEDLINE(name,i)=Do Not Disturb: ON)
exten => *78,n,Set(CONNECTEDLINE(num,i)=${AMPUSER})
exten => *78,n,Answer
exten => *78,n,Wait(1)
exten => *78,n,Set(DB(DND/${AMPUSER})=YES)
exten => *78,n,Set(STATE=ONHOLD)
exten => *78,n,Gosub(app-dnd-on,sstate,1())
exten => *78,n(hook_1),Playback(do-not-disturb&activated)
exten => *78,n,Macro(hangupcall,)

Warum auch immer werden extesions von freepbx korrekt als unavailable erkannt, wenn die Identity sich abmeldet, aber der Status des hints hüpft nicht auf Unavailable.

Also schnell ein kleines python script gebaut, das alle 5 Sekunden die extensions kontrolliert und den hint aktualisiert wenn notwendig. Ginge vermutlich sauberer, wenn ein Script dauernd läuft und das event abfängt, aber egal.

"""
Example to get list of active channels
"""
import asterisk.manager
import sys

endpoints = {12,13,14,15,16,17,18}

manager = asterisk.manager.Manager()
check_update = [] #extensions to check for update
update = [] #extensions to update
try:
    # connect to the manager
    try:
		manager.connect('localhost')
		manager.login('logoff_user', 'PASSWORD')

		# get a status report
		response = manager.status()
		#print(response)
		response = manager.command('pjsip list endpoints')
		#print(response.data)
		data = response.data
		for endpoint in endpoints:
			start = str(response.data.encode('utf-8')).find(str(endpoint)+'/'+str(endpoint))
			end = start + 70
			test = data[start:end].find('Unavailable')
			if test > -1:
				#extension is Unavailable
				check_update.append(endpoint)
		###### check if hint is already set to unavailable, if not update
		import pdb
		pdb.set_trace()
		response = manager.command('core show hints')
		#print(response.data)
		data = response.data
		for endpoint in check_update:
			start = str(response.data.encode('utf-8')).find(str(endpoint)+'@ext-local')
			end = start + 60
			test = data[start:end].find('Unavailable')
			if test == -1:
				#extension is Unavailable
				update.append(endpoint)
		for extension in update:
			response = manager.command('devstate change Custom:DND'+str(extension)+' UNAVAILABLE')
			#print(response.data)
		manager.logoff()
    except asterisk.manager.ManagerSocketException as e:
        print "Error connecting to the manager: %s" % e.strerror
        sys.exit(1)
    except asterisk.manager.ManagerAuthException as e:
        print "Error logging in to the manager: %s" % e.strerror
        sys.exit(1)
    except asterisk.manager.ManagerException as e:
        print "Error: %s" % e.strerror
        sys.exit(1)

finally:
    # remember to clean up
    manager.close()

weil das Script alle 5 Sekunden laufen soll, hilft mir cron nicht, das kann nur ganze Minuten. Hier habe ich aber was gefunden das wunderbar klappt: https://stackoverflow.com/questions/9619362/running-a-cron-every-30-seconds

und dann noch die handgeschnitzte XML Definition für die Tasten:

<general type="AsteriskPresenceField"/>

<initialization>

  <state value='initial'/>

  <variable name='subscr_ext' value='12'/>

  <variable name='subscr_proxy' value='xxx.xxx.xxx.xxx'/>

  <variable name='pickup_code' value='*8$(subscr_ext)'/>

  <variable name='subscr_uri' value='sip:$(subscr_ext)@$(subscr_proxy)'/>

  <identity value='1'/>

</initialization>

<subscription type="presence" to="&lt;$(subscr_uri)&gt;" for="$(subscr_uri)"/>

<NotifyParsingRules type="applies">     
  <level1 translates_to='OK'>/presence[@entity="$(subscr_uri):5060"]</level1>   <!-- OKAY-->
</NotifyParsingRules>   
<NotifyParsingRules type="state">
  <level1 translates_to="ringing">/dialog-info/dialog/state[.="early"]</level1>
  <level1-1 translates_to="CALLING">/dialog-info/dialog[@direction="initiator"]</level1-1>
  <level2 translates_to="ringing">/presence/note[.="Ringing"]</level2><!--OKAY-->
  <level2-1 translates_to="CALLING">/dialog-info/dialog[@direction="initiator"]</level2-1>
  <level3 translates_to="IN_A_CALL">/presence/note[.="On the phone"]</level3><!-- OKAY-->
  <level4 translates_to="NOT_IN_USE">/presence/note[.="Ready"]</level4><!-- OKAY-->
  <level5 translates_to="OFFLINE">/presence/tuple/status/basic[.="closed"]</level5><!-- OKAY-->
  <level6 translates_to="DND">/presence/note[.="On hold"]</level6><!-- OKAY-->
  <level7 translates_to="free"/>
</NotifyParsingRules>
<NotifyParsingRules type="variable" id="call_id" state="ringing">     
  <level1 fetch_attribute="call-id">/dialog-info/dialog[@call-id]</level1>   
</NotifyParsingRules>   
<NotifyParsingRules type="variable" id="remote_tag" state="ringing">     
  <level1 fetch_attribute="remote-tag">/dialog-info/dialog[@remote-tag]</level1>   
</NotifyParsingRules>   
<NotifyParsingRules type="variable" id="local_tag" state="ringing">     
  <level1 fetch_attribute="local-tag">/dialog-info/dialog[@local-tag]</level1>   
</NotifyParsingRules>   
<NotifyParsingRules type="variable" id="remote_uri" state="ringing">     
  <level1 fetch_attribute="uri">/dialog-info/dialog/remote/target[@uri]</level1>   
</NotifyParsingRules>  
<NotifyParsingRules type="variable" id="remote_name" state="ringing">     
  <level1 fetch_attribute="display">/dialog-info/dialog/remote/identity[@display]</level1>   
</NotifyParsingRules>

<action>   
  <invite target="$(remote_name)<$(remote_uri)>" when="on press" state="ringing" request_uri="$(remote_uri)" replaces="$(call_id);to-tag=$(remote_tag);from-tag=$(local_tag)"/>
  <dial target="$(subscr_uri)" when="on press"/> 
</action>