DS2450 als Multisensor für Temperatur, Luftfeuchte, Helligkeit und Luftdruck

Der DS2450 ist ideal für die Verwendung zur Abfrage verschiedener Sensoren. Leider wird er nicht von allen Smarthome-Systemen unterstützt. So ist dieser Sensor nicht im Web-Interface von Wiregate enthalten. Auch die Loxone 1-Wire Extension unterstützt diese Sensoren bis jetzt noch nicht.

KanalABCD
WerteTemperaturFeuchteHelligkeitDruck
F
o
r
m
e
l
16 Bit (0..65535)(W-32767)/100W/100EXP((W-32767)/1000) EXP ist die Expotentialfunktion also e hoch xW/32
0..5,12V(W-2,56)*128W*128EXP((W-2,56)*12,8)W*400
0..2,56V(W-1,28)*256W*256EXP((W-1,56)*25,6)W*800
B
e
i
s
p
.
16 Bit34890503933450 31323
0..5,12V2.725820.3936782.613322.44715
0..2,56V1,36291 0,1968391,30666 1,223575
Wert21,2 °C 50,4 %1,98 Lux 978,8 hPa

Je nach Ausführung sind nicht alle Sensoren belegt. Der fehlende Wert ist dann "0".

Informationen zum Auslesen

FHEM

In FHEM gibt es das Attribut "userReadings". Je nachdem ob man OWX oder OWFS für die 1-Wire-Schnittstelle benutzt, müssen verschiedene Werte eingetragen werden.

OWX:
Temperatur {sprintf("%0.1f",(ReadingsVal("$name","A",0)-2.56)*128)},Feuchte {sprintf("%0.2f",ReadingsVal("$name","B",0)*128)},Helligkeit {sprintf("%0.2f",exp((ReadingsVal("$name","C",0)-2.56)*12.8))} ,Luftdruck {sprintf("%0.1f",ReadingsVal("$name","D",0)*400)}

OWFS:
Temperatur {sprintf("%0.1f",(ReadingsVal("$name","volt.A",0)-2.56)*128)},Feuchte {sprintf("%0.2f",ReadingsVal("$name","volt.B",0)*128)},Helligkeit {sprintf("%0.2f",exp((ReadingsVal("$name","volt.C",0)-2.56)*12.8))} ,Luftdruck {sprintf("%0.1f",ReadingsVal("$name","volt.D",0)*400)}

In der fhem.cfg sieht das Ganze dann zum Beispiel so aus (OWX):

define ow1 OWX /dev/ttyUSB0
define OWX_20_E4D984000003 OWAD DS2450 E4D984000003
attr OWX_20_E4D984000003 IODev ow1
attr OWX_20_E4D984000003 model DS2450
attr OWX_20_E4D984000003 room OWX
attr OWX_20_E4D984000003 userReadings Temperatur {sprintf("%0.1f",(ReadingsVal("$name","A",0)-2.56)*128)},Feuchte {sprintf("%0.2f",ReadingsVal("$name","B",0)*128)},Helligkeit {sprintf("%0.2f",exp((ReadingsVal("$name","C",0)-2.56)*12.8))} ,Luftdruck {sprintf("%0.1f",ReadingsVal("$name","D",0)*400)}

Python mit w1-Kernelmodul

In neuern Linux-Kernels gibt es das w1-Kernelmodul, welches die 1-Wire Schnittstelle in einer Verzeichnisstruktur unter /sys/bus/w1 abbildet. Der Zugriff darüber ist vor allem auf dem RaspberryPi weit verbreitet, weil der GPIO4 Anschluss direkt als 1-Wire Master verwendet werden kann.

Die Werte einiger 1-Wire Devices sind über spezielle Module zugänglich wie z.B. der DS18B20 über das Modul therm. Für den DS2450 gibt es kein Modul aber eine Datei mit dem Namen rw über die mit dem Gerät kommuniziert werden kann. Leider ist das Schreiben nur als root möglich. Die Rechte lassen sich zwar ändern aber bei jedem neuen verbinden gehen diese Änderungen verloren (Vieleicht gibt es je einige Linux-Experten die mir verraten können wie man das ändert). Am besten startet man die Python Skripte also als root (sudo python ....).

In der Git-Repository unter owPython ist ein ausführlicher Beispielcode zu finden. Die wichtigste Routine dabei ist die Funktion owcom in der Datei owlib.py.

def owcom(dev,send,rc):
	#standard Rueckgabe bei rc=0 oder Fehler
	res=[0xFF]*rc
	err=0
	try:
		#rw-Datei fuer Lesen und Schreiben oeffnen ohne Buffer (,0) 
		f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
	except IOError:
		print "ERROR open rw-File, try unload modules w1_therm, w1_smem and w1_ds2433"
		try:
			#Kernel-Module fuer spezielle 1-Wire-Chips entfernen und neu versuchen.
			l=subprocess.check_output("rmmod w1_therm w1_smem w1_ds2433",shell=True)
		except:
			print "ERROR unload modules"
		err=1
	if (err): 
		try:
			f=open("/sys/bus/w1/devices/%s/rw" %(dev),"r+b",0)
			err=0
		except IOError:
			print "ERROR open rw-File"
			return res
	#byte-Array in String konvertieren und senden
	f.write("".join(map(chr, send)))
	if (rc!=0):
		#empfangene Bytes wieder in Array (Liste) umwandeln
		res=map(ord,f.read(rc))
	f.close()
	return res

PHP mit w1-Kernelmodul

Immer öfter möchten Leute die die w1-Verzeichnisse mit PHP auslesen. Für den DS18B20 gibt es da einen einfachen Code im www. Leider ist es mit dem DS2450 nicht ganz so einfach, aber es geht ohne Probleme (Administratorrechte vorausgesetzt). Deshalb an dieser Stelle noch ein "kleines" Codebeispiel welches Temperatur, Feuchte und Luftdruck ausgibt:

<?php
//CRC16 zum CRC-Check
function crc16($arr) {
	$oddparity = array( 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 );
	$crc16=0;
	foreach($arr as $cdata) {
		$cdata = ($cdata ^ ($crc16 & 0xff)) & 0xff;
		$crc16 = $crc16>>8;
		if ($oddparity[$cdata & 0xf] ^ $oddparity[$cdata >> 4]) 
			$crc16 = $crc16 ^ 0xc001;
		$cdata = ($cdata << 6)&0xffff;
		$crc16  = $crc16 ^ $cdata;
		$cdata = ($cdata << 1)&0xffff;
		$crc16  = $crc16^$cdata;
	}
	return ($crc16==0xB001);
}

//Funktion zum Senden und Empfangen durch die rw-Datei
function owcom($dev,$send,$rc) {
	$res=array();
	try {
		$f=fopen("/sys/bus/w1/devices/".$dev."/rw" ,"rb+",0);
    }
	 catch (Exception $e)  {
		echo "Error open rw-File";
	}
    //Wichtig, ohne Buffer lesen!!!!
	stream_set_read_buffer ( $f ,0 );
	//Array in String umwandeln
    $s=pack("C*",...$send);
	fwrite($f,$s,strlen($s));
    //String wieder in Array umwandlen
	if ($rc!=0) $res=unpack("C*",fread($f,$rc));
	fclose($f);
	return $res;
}		

//Konvertieren und Lesen der RAW werte vom DS2450
function readDS2450($dev) {
	$res=array(0,0,0,0);
    //Befehl Konvertiere alle Kanaele senden
	$ret=owcom($dev,array(0x3C,0x0F,0x00),2);
	if (crc16(array_merge(array(0x3C,0x0F,0x00),$ret))!=1) {
		echo("CRC ERROR\n");
		return $res;
	}
	usleep(100);
    //Auslesend er Ergebnisse
	$ret=owcom($dev,array(0xAA,0x00,0x00),10);			
	if (crc16(array_merge(array(0xAA,0x00,0x00),$ret))!=1) {
		echo("CRC ERROR\n");
		return $res;
	}
	$res[1]=$ret[1]|($ret[2]<<8);
	$res[2]=$ret[3]|($ret[4]<<8);
	$res[3]=$ret[5]|($ret[6]<<8);
	$res[4]=$ret[7]|($ret[8]<<8);
	return $res;
}

//Verzeichnis der 1-Wire Devices auslesen
$devlist=scandir ( "/sys/bus/w1/devices/");
//Hoehenkorrektur fuer den Luftdruck
$hoehe=320;
$hoehe_f=pow(1-$hoehe/44330,5.255);

//Verzeichniss durchsuchen
foreach($devlist as $dev) {
	if (strlen($dev)>=3) {
		echo $dev."\n";
		if ($dev[2]=="-") { //Ist Eintrag eine 1-Wire-ID?
			if (substr($dev,0,2)=="20") {  //DS2450?
				echo "DS2450 found\n";
				$ret=readDS2450($dev); //DS2450 auslesen
				$temp=($ret[1]-32767)/100;
				$hum=$ret[2]/100;
				$press=$ret[4]/32;
				echo "Temperatur=".$temp."\n";
				echo "Feuchte=".$hum."\n";
				echo "Druck=".$press."\n";
				echo "Druck(Hoehenkorrketur)=".$press/$hoehe_f."\n";
			}
		}		 
	}
}
?>

Zum Seitenanfang