dkUtils ist eine Sammlung an nützlichen FHEM Funktionen, die Du für die Programmierung Deiner Hausautomation verwenden kannst. Sie bildet die Basis für meine Hausautomation und erleichtert mir das Leben ungemein.

Im Folgenden stelle ich Dir die einzelnen Funktionen kurz vor.

dkUtils.pm: Allgemeine Is Funktionen

sub dkIsHomematic($) {
	my ($device) = @_;	
	my $device_type = dkGetAttr($device, "model");
	if (substr($device_type, 0, 2) eq "HM") {
		return 1;
	} else {
		return 0;
	}
}

sub dkIsAction($) {
	my ($device) = @_;
	if (substr($device, 0, 7) eq "Action_") {
		return 1;
	} else {
		return 0;
	}
}

sub dkIsOn($) {
	my ($input) = @_;	
	my @devices = split(',', $input);
	my @active_devices;
	
	foreach my $device (@devices) {
		if (dkExists($device)) {
			my $state = dkGetState($device);
			if ($state eq "on") {
				push(@active_devices, dkGetAlias($device));
			}
		}
	}
	return join(", ", sort(@active_devices) );
}

sub dkIsWinter() {
	my $is_winter = dkGetState("setting_winter");
	if ($is_winter eq "on") { return 1; } else { return 0; }
}

sub dkIsXmas() {
	my $is_xmas = dkGetState("setting_xmas");
	if ($is_xmas eq "on") { return 1; } else { return 0; }
}

sub dkIsDND() {
	my $is_xmas = dkGetState("setting_dnd");
	if ($is_xmas eq "on") { return 1; } else { return 0; }
}

sub dkIsParentsHome() {
	my $is_parents_home = dkGetState("rgr_Parents");
	if ($is_parents_home eq "home") { return 1; } else { return 0; }
}

sub dkIsScharf() {
	my $is_scharf = dkGetState("data_anlagenstatus");
	if ( $is_scharf eq "unscharf" ) { return 0; } else { return 1; }
}

Mit obigen Funktionen kann man bestimmte Zustände und Settings überprüfen. An die Funktion dkIsOn() kann man kommasepariert mehrere Geräte übergeben.

dkUtils.pm: Allgemeine Set Funktionen

sub dkSetState($$) {
	my ($device, $value) = @_;	
	fhem("setstate $device $value", 1);
}

sub dkSetDevice($$) {
	my ($input, $value) = @_;	
	my @devices = split(',', $input);
	my @validated_devices;

	foreach my $device (@devices) {
		if (dkExists($device)) {
			if (dkIsHomematic($device)) {
				my $state = dkGetState($device);
				if ($state ne $value && $state ne "unknown") {
					push(@validated_devices, $device);
				}
			} else {
				push(@validated_devices, $device);
			}
		}
	}

	my $cleaned_device_list = join(",", @validated_devices);
	if ($cleaned_device_list ne "") {
		fhem("set $cleaned_device_list $value", 1);
	}		
}

sub dkOn($) {
	my($device) = @_;
	dkSetDevice($device, "on");
}

sub dkOff($) {
	my($device) = @_;
	dkSetDevice($device, "off");
}

sub dkToggle($) {
	my ($device) = @_;
	fhem("set $device toggle", 1);
}

sub dkOnFor($$) {
	my ($device, $durationInHours) = @_;
	if (dkGetState($device) eq "on") { return 0; }
	
	dkOn($device);
	dkAutoOff($device, "on", $durationInHours);
}

Diese Funktionen schalten Geräte ein oder aus, bzw. ändern deren Zustand abhängig davon ob sie gerade ein- oder ausgeschaltet sind.

sub dkAutoOff($$$) {
	my ($device, $event, $durationInHours) = @_;
	my ($deviceAutoOff) = $device . "_AutoOff";	
	if (dkExists($deviceAutoOff)) { fhem ("delete $deviceAutoOff"); }
	if ($event eq "on") {
		my $mytime = dkTimeAddHoursHMS($durationInHours);
		fhem ("define $deviceAutoOff at $mytime { dkOff('$device') }", 1);
	}
}

sub dkAutoOffDelete($) {
	my ($device) = @_;
	my ($deviceAutoOff) = $device . "_AutoOff";	
	if (dkExists($device)) { fhem("delete $deviceAutoOff", 1); }
}

Die Funktion dkAutoOff sorgt dafür, dass ein Gerät nach einer gewissen Zeit in Stunden (0.5 für eine halbe Stunde geht auch) ausgeschaltet wird. Dies könnte man auch über „on-till“ oder „on-for-timer“ jedoch lösen diese Timer im Falle eines Neustarts nicht aus.
Achtung: Diese Funktion hat weitere Abhängigkeiten. Zum einen dkExists() (prüft ob Gerät vorhanden) und dkTimeAddHoursHMS() (addiert zur aktuellen Zeit x Stunden).
Eine ausführliche Beschreibung findet ihr in dem Beitrag AutoOff für Geräte erstellen.

dkUtils.pm: Zustände, Gerätenamen und Parameter

sub dkGetReading($$){
	my($device, $reading) = @_;
	return ReadingsVal($device, $reading, "unknown");
}

sub dkGetState($){
	my($device) = @_;
	return ReadingsVal($device, "state", "unknown");
}

sub dkGetStateLastChange($) {
	my($device) = @_;	
	return ReadingsTimestamp($device,"state","0");
}

sub dkGetAttr($$) {
	my($device, $attr) = @_;	
	return AttrVal($device, $attr, "unknown");
}

sub dkGetAlias($) {
	my($device) = @_;	
	return AttrVal($device, "alias", "unknown");
}

sub dkSetValue($$) {
	my($device, $value) = @_;
	fhem("set $device $value");
}

sub dkSetReading($$$) {
	my($device, $reading, $value) = @_;
	fhem("setreading $device $reading $value");
}

#######################################

sub dkExists($) {
	my ($object) = @_;
	if ( Value($object) ) {	return 1; } else { return 0; }
}

sub dkValueExists($) {
	my ($object) = @_;
	if ( Value($object) eq "???" || ReadingsVal($object, "state", "???") eq "???" ) {
		return 0;
	} else {
		return 1;
	}
}

Mit den obigen Funktionen kann ich relativ einfach einen Gerätenamen (Alias) sowie Werte und Zustände von Geräten abfragen und setzen. Darüber hinaus kann überprüft werden, ob ein Gerät bzw. ein Value existiert.

dkUtils.pm: Watchdog

sub dkWatchdog($$$) {
	my ($device, $state, $durationInHours) = @_;
	my $device_state = dkGetState($device);
	my $device_alias = dkGetAlias($device);
	
	dkRemoveWatchdog($device);
	if ($device_state eq $state) {
		dkAddWatchdog($device,$state,$durationInHours);
		dkPush("device", "$device_alias ist noch angeschaltet.");
	} 
}

sub dkAddWatchdog($$$) {
	my($device, $state, $durationInHours) = @_;
	my $device_notify = $device . "_dkWatchdog";
	my $mytime = dkTimeAddHoursHMS($durationInHours);
	fhem("define $device_notify at $mytime { dkWatchdog('$device', '$state', $durationInHours) }");
}

sub dkRemoveWatchdog($) {
	my($device) = @_;
	my $device_notify = $device . "_dkWatchdog";
	if (dkExists($device_notify)) {
		fhem ("delete $device_notify");
	}
}

Mein dkWatchdog sorgt dafür, dass nach einer bestimmten Zeit überprüft wird, ob ein Gerät noch angeschaltet ist. Schalte ich z. B. eine Pumpe an, so wird der Watchdog gesetzt (dkAddWatchdog), schalte ich sie aus, wird der Watchdog wieder gelöscht (dkRemoveWatchdog). Nach dem Anschalten wird z. B. nach einer Stunde überprüft (dkWatchdog), ob das Gerät noch an ist und entsprechend eine Push-Notification verschickt. So kann sichergestellt werden, dass man nie vergisst Geräte wieder auszuschalten.

dkUtils.pm: Zeit-Funktionen

sub dkCurrentHour($$) {
	my ($operator,$hour) = @_;
	my $currenthour = strftime("%H", localtime)+0; # +0 = hack to format as integer
	my $command = "$currenthour $operator $hour";
	if (eval($command)) {
		return 1;
	} else {
		return 0;
	}
}

sub dkTimeFormat($){
	my $Sekundenzahl = @_;
	return sprintf("%02d:%02d:%02d", ($Sekundenzahl/60/60)%24, ($Sekundenzahl/60)%60, ($Sekundenzahl)%60 );
}

sub dkTimeAgeInHours($$) {
	my ($now, $timestamp) = @_;
	my @splitdatetime = split(/ /,$timestamp);
	my @splitdate = split(/-/, $splitdatetime[0]);
	my @splittime = split(/:/, $splitdatetime[1]);
	my $last_state_time =  timelocal($splittime[2], $splittime[1], $splittime[0], $splitdate[2], $splitdate[1]-1, $splitdate[0]);
	my $age_in_hours = ($now - $last_state_time) / 3600;		
	return $age_in_hours;
}

sub dkTimeHoursToHMS($) {
	my ($hours) = @_;
	$hours = $hours * 60 * 60;
	return strftime("\%H:\%M:\%S", gmtime($hours) );
}

sub dkTimeAddHoursHMS($) {
	my ($hours) = @_;
	$hours = $hours * 60 * 60;
	return strftime("\%H:\%M:\%S", localtime(time + $hours) );
}

Diese Funktionen konvertieren oder berechnen Timestamps oder HMS-Zeitangaben (also Stunde:Minute:Sekunde).
Die Funktion dkTimeAgeInHours kann z. B. dafür verwendet werden, um herauszufinden, ob sich ein Wert innerhalb einer bestimmten Zeit verändert hat.

dkUtils.pm: Sprachausgabe

sub dkTalk($) {
	my ($message) = @_;
	if (!$message) { return; }
	$message =~ s/_/ /g;
	$message =~ s/-/ /g;
	fhem("set mytts tts $message");
}


dkTalk ermöglicht die Sprachausgabe. Bevor die Nachricht an das Gerät übermittelt wird, werden "_" und "-" entfernt, damit eine unterbrechungsfreie Ausgabe erfolgt und diese Zeichen nicht gesprochen werden.

<h2>dkUtils.pm: Push-Nachrichten</h2>

sub dkPush($$) {
	my ($type, $message) = @_;
	if (!$message) { return; }
	if ($type eq "default") 	{ fhem("set pushover msg '$message'"); }
	if ($type eq "warning") 	{ fhem("set pushover msg 'FHEM Warning' '$message' '' 0 'gamelan' "); }
	if ($type eq "call") 		{ fhem("set pushover msg 'FHEM' '$message' '' 0 'bike' "); }
	if ($type eq "device") 		{ fhem("set pushover msg 'FHEM' '$message' '' 0 'bike' "); }
	if ($type eq "attention") 	{ fhem("set pushover msg 'FHEM' '$message' '' 0 'bugle' "); }
	if ($type eq "magic") 		{ fhem("set pushover msg 'FHEM' '$message' '' 0 'magic' "); }
}

Mit dkPush können Push-Nachrichten angestoßen werden. Je nach gesetzten Type ertönt in der App ein anderer Signalton.

dkUtils.pm: Textausgabe auf Fernseher

sub dkDisplayText($) {
	my ($message) = @_;
	if (!$message) { return; }
	if ( ReadingsVal("SatReceiver", "presence", "unknown") eq "present") {
		fhem("set SatReceiver msg info 10 $message");
	}
}

Diese Funktion sorgt dafür, dass auf meinem Enigma2-Sat-Receiver ein Mitteilung erscheint (z. B. wenn eine Anruf eingeht).

dkUtils.pm: FHEM-Start/Stop

sub dkFHEM($) {
	my ($event) = @_;
	
	if ($event eq "INITIALIZED") {
		dkSetDefaults();
		fhem("set SCC led 00");
		dkTalk("System gestartet.");
	}
	
	if ($event eq "SHUTDOWN") {
		dkTalk("System fährt runter.");
	}
	
}

Je nach Status von FHEM (Initialized oder Shutdown) erfolgt eine kurze Sprachausgabe.