From 4ad06be1260b740e013f879af6e05cfffd2a01b7 Mon Sep 17 00:00:00 2001 From: pahenning Date: Mon, 25 Apr 2016 18:52:01 +0000 Subject: [PATCH] DoorPi.pm: zur Anbindung des DoorPi-Projektes git-svn-id: https://svn.fhem.de/fhem/trunk@11312 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DoorPi/70_DoorPi.pm | 788 ++++++++++++++++++++++++++++ fhem/contrib/DoorPi/doorpi.ini.safe | 146 ++++++ fhem/contrib/DoorPi/getparams.sh | 7 + fhem/contrib/DoorPi/iButton_NOK.sh | 5 + fhem/contrib/DoorPi/iButton_OK.sh | 6 + fhem/contrib/DoorPi/purge.sh | 19 + 6 files changed, 971 insertions(+) create mode 100644 fhem/contrib/DoorPi/70_DoorPi.pm create mode 100644 fhem/contrib/DoorPi/doorpi.ini.safe create mode 100755 fhem/contrib/DoorPi/getparams.sh create mode 100755 fhem/contrib/DoorPi/iButton_NOK.sh create mode 100755 fhem/contrib/DoorPi/iButton_OK.sh create mode 100755 fhem/contrib/DoorPi/purge.sh diff --git a/fhem/contrib/DoorPi/70_DoorPi.pm b/fhem/contrib/DoorPi/70_DoorPi.pm new file mode 100644 index 000000000..3b429d6e5 --- /dev/null +++ b/fhem/contrib/DoorPi/70_DoorPi.pm @@ -0,0 +1,788 @@ +######################################################################################## +# +# DoorPi.pm +# +# FHEM module to communite with a Raspberry Pi door station +# +# Prof. Dr. Peter A. Henning, 2016 +# +# Version 0.2 - April 2016 +# +######################################################################################## +# +# This programm is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The GNU General Public License can be found at +# http://www.gnu.org/copyleft/gpl.html. +# A copy is found in the textfile GPL.txt and important notices to the license +# from the author is found in LICENSE.txt distributed with these scripts. +# +# This script is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +######################################################################################## +package main; + +use strict; +use warnings; + +use JSON; # imports encode_json, decode_json, to_json and from_json. + +use vars qw{%attr %defs}; + +sub Log($$); + +#-- globals on start + +#-- these we may get on request +my %gets = ( + "config" => "C", + "history" => "H" +); + + +######################################################################################## +# +# DoorPi_Initialize +# +# Parameter hash +# +######################################################################################## + +sub DoorPi_Initialize ($) { + my ($hash) = @_; + + $hash->{DefFn} = "DoorPi_Define"; + $hash->{UndefFn} = "DoorPi_Undef"; + $hash->{AttrFn} = "DoorPi_Attr"; + $hash->{GetFn} = "DoorPi_Get"; + $hash->{SetFn} = "DoorPi_Set"; + #$hash->{NotifyFn} = "DoorPi_Notify"; + $hash->{InitFn} = "DoorPi_Init"; + + $hash->{AttrList}= "verbose ". + "language:de,en ". + "doorbutton dooropencmd doorlockcmd doorunlockcmd ". + "lightbutton lightoncmd lighttimercmd lightoffcmd ". + $readingFnAttributes; + + $hash->{FW_detailFn} = "DoorPi_makeTable"; + $hash->{FW_summaryFn} = "DoorPi_makeTable"; + $hash->{FW_atPageEnd} = 1; +} + +######################################################################################## +# +# DoorPi_Define - Implements DefFn function +# +# Parameter hash, definition string +# +######################################################################################## + +sub DoorPi_Define($$) { + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + return "[DoorPi] Define the IP address of DoorPi as a parameter" + if(@a != 3); + return "[DoorPi] Invalid IP address of DoorPi" + if( $a[2] !~ m|\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?(\:\d+)?| ); + + my $dev = $a[2]; + #-- split into parts + my @tcp = split(':',$dev); + #-- when the specified ip address contains a port already, use it as supplied + if ( $tcp[1] ){ + $hash->{TCPIP} = $dev; + }else{ + $hash->{TCPIP} = $tcp[0].":80"; + }; + + @{$hash->{DATA}} = (); + @{$hash->{CMDS}} = (); + + $modules{DoorPi}{defptr}{$a[0]} = $hash; + + #-- InternalTimer blocks if init_done is not true + my $oid = $init_done; + $init_done = 1; + readingsSingleUpdate($hash,"state","initialized",1); + + DoorPi_GetConfig($hash); + DoorPi_GetHistory($hash); + $init_done = $oid; + return undef; +} + +####################################################################################### +# +# DoorPi_Undef - Implements UndefFn function +# +# Parameter hash = hash of device addressed +# +####################################################################################### + +sub DoorPi_Undef ($) { + my ($hash) = @_; + delete($modules{DoorPi}{defptr}{NAME}); + RemoveInternalTimer($hash); + return undef; +} + +####################################################################################### +# +# DoorPi_Attr - Set one attribute value +# +# Parameter hash = hash of device addressed +# a = argument array +# +######################################################################################## + +sub DoorPi_Attr(@) { + my ($do,$name,$key,$value) = @_; + + my $hash = $main::defs{$name}; + my $ret; + + if ( $do eq "set") { + ARGUMENT_HANDLER: { + $key eq "interval" and do { + $hash->{interval} = $value; + if ($main::init_done) { + # WHAT ? + } + last; + }; + } + } + return $ret; +} + +######################################################################################## +# +# DoorPi_Get - Implements GetFn function +# +# Parameter hash, argument array +# +######################################################################################## + +sub DoorPi_Get ($@) { + my ($hash, @a) = @_; + + #-- for the selector: which values are possible + #if ($a[1] eq "?"){ + # my $newkeys = join(" ",sort keys %gets); + # Log 1,"=====> newkeys before subs $newkeys"; + # $newkeys =~ s/config/config:noArg/g; # FHEMWEB sugar + # $newkeys =~ s/history/history:noArg/g; # FHEMWEB sugar + # Log 1,"=====> newkeys after subs $newkeys"; + # return $newkeys; + #} + + #-- check syntax + return "[DoorPi] DoorPi_Get needs exactly one parameter" if(@a != 2); + my $name = $hash->{NAME}; + my $v; + + #-- current configuration + if($a[1] eq "config") { + $v = DoorPi_GetConfig($hash); + if(defined($v)) { + Log GetLogLevel($name,2), "DoorPi_Get $a[1] error"; + return "$a[0] $a[1] => Error"; + } + $v = "OK"; + #-- current reading + }elsif($a[1] eq "history") { + $v = DoorPi_GetHistory($hash); + if(defined($v)) { + Log GetLogLevel($name,2), "DoorPi_Get $a[1] error"; + return "$a[0] $a[1] => Error"; + } + $v = "OK"; + } else { + return "DoorPi_Get with unknown argument $a[1], choose one of " . join(" ", sort keys %gets); + } + + Log GetLogLevel($name,3), "DoorPi_Get $a[1] $v"; + return "$a[0] $a[1] => $v"; +} + +######################################################################################## +# +# DoorPi_Set - Implements SetFn function +# +# Parameter hash, a = argument array +# +######################################################################################## + +sub DoorPi_Set ($@) { + my ($hash, @a) = @_; + my $name = shift @a; + my ($key,$value,$res); + + #-- commands + my $door = AttrVal($name, "doorbutton", "door"); + my $doorsubs = "open"; + $doorsubs .= ",lock" + if(AttrVal($name, "doorlockcmd",undef)); + $doorsubs .= ",unlock" + if(AttrVal($name, "doorunlockcmd",undef)); + + my $light = AttrVal($name, "lightbutton", "light"); + + #-- for the selector: which values are possible + if ($a[0] eq "?"){ + my $newkeys = join(" ",@{ $hash->{CMDS} }); + #Log 1,"=====> newkeys before subs $newkeys"; + $newkeys =~ s/$door/$door:$doorsubs/g; # FHEMWEB sugar + $newkeys =~ s/$light/$light:on,on-for-timer,off/g; # FHEMWEB sugar + $newkeys =~ s/button(\d\d?)/button$1:noArg/g; # FHEMWEB sugar + $newkeys =~ s/purge/purge:noArg/g; # FHEMWEB sugar + #Log 1,"=====> newkeys after subs $newkeys ($door,$light)"; + return $newkeys; + } + + #return "[DoorPi_Set] With unknown argument $a[0], choose one of " . join(" ", @{$hash->{CMDS}}) + # if(!defined($sets{$a[0]})); + + $key = shift @a; + $value = shift @a; + + if( $key eq "door" ){ + if( $value eq "open" ){ + $res=DoorPi_Cmd($hash,"door"); + #Log 1,"[DoorPiCmd] open door has result $res"; + if(AttrVal($name, "dooropencmd",undef)){ + fhem(AttrVal($name, "dooropencmd",undef)); + } + } + }elsif( $key =~ /button(\d\d?)/){ + $res=DoorPi_Cmd($hash,$key); + Log 1,"[DoorPiCmd] $key has result $res"; + }elsif( $key eq "purge"){ + $res=DoorPi_Cmd($hash,"purge"); + Log 1,"[DoorPiCmd] purge has result $res"; + }elsif( $key eq "clear"){ + $res=DoorPi_Cmd($hash,"clear"); + Log 1,"[DoorPiCmd] clear has result $res"; + } + + #Log GetLogLevel($name,3), "DoorPi_Set $name ".join(" ",@a)." => $res"; + #return "DoorPi_Set $name ".join(" ",@a)." => $res"; +} + +####################################################################################### +# +# DoorPi_GetConfig - acts as callable program DoorPi_GetConfig($hash) +# and as callback program DoorPi_GetConfig($hash,$err,$status) +# +# Parameter hash, err, status +# +####################################################################################### + +sub DoorPi_GetConfig () { + my ($hash,$err,$status) = @_; + my $name = $hash->{NAME}; + my $url; + + #-- get configuration from doorpi + if ( !$hash ){ + Log 1,"[DoorPi_GetConfig] called without hash"; + return undef; + }elsif ( $hash && !$err && !$status ){ + $url = "http://".$hash->{TCPIP}."/status?module=config"; + Log 1,"[DoorPi_GetConfig] called with only hash => Issue a non-blocking call to $url"; + HttpUtils_NonblockingGet({ + url => $url, + callback=>sub($$$){ DoorPi_GetConfig($hash,$_[1],$_[2]) } + }); + return undef; + }elsif ( $hash && $err ){ + Log 1,"[DoorPi_GetConfig] called with only hash and error $err"; + return undef; + } + Log 1,"[DoorPi_GetConfig] has obtained data"; + + #-- crude test if this is valid JSON or some HTML page + if( substr($status,0,1) eq "<" ){ + Log 1,"[DoorPi_GetConfig] but data is invalid"; + return; + } + + my $json = JSON->new->utf8; + my $jhash0 = $json->decode( $status ); + + #-- decode config + my $keyboards = $jhash0->{"config"}->{"keyboards"}; + my $fskey; + my $fscmds; + foreach my $key (sort(keys $keyboards)) { + $fskey = $key + if( $keyboards->{$key} eq "filesystem"); + } + if($fskey){ + Log 1,"[DoorPi_GetConfig] keyboard \'filesystem\' defined as '$fskey'"; + $hash->{HELPER}->{vkeyboard}=$fskey; + $fscmds = $jhash0->{"config"}->{$fskey."_InputPins"}; + foreach my $key (sort(keys $fscmds)) { + push(@{ $hash->{CMDS}},$key); + } + }else{ + Log 1,"[DoorPi_GetConfig] Warning: No keyboard \"filesystem\" defined"; + }; + $hash->{HELPER}->{wwwpath} = $jhash0->{"config"}->{"DoorPiWeb"}->{"www"}; + + + #=================== Put into READINGS + ##readingsBeginUpdate($hash); + ##readingsBulkUpdate($hash,"status_time",$jhash0->{"status_time"}); + ##readingsBulkUpdate($hash,"number_calls",int(@{ $hash->{DATA}})); + ##readingsEndUpdate($hash,1); + + return undef; +} + +####################################################################################### +# +# DoorPi_GetHistory - acts as callable program DoorPi_GetHistory($hash) +# and as callback program DoorPi_GetHistory($hash,$err1,$status1) +# and as callback program DoorPi_GetHistory($hash,$err1,$status1,$err2,$status2) +# +# Parameter hash +# +####################################################################################### + +sub DoorPi_GetHistory () { + my ($hash,$err1,$status1,$err2,$status2) = @_; + my $name = $hash->{NAME}; + my $url; + + #-- obtain call history and snapshot history from doorpi + if ( !$hash ){ + Log 1,"[DoorPi_GetHistory] called without hash"; + return undef; + }elsif ( $hash && !$err1 && !$status1 && !$err2 && !$status2 ){ + $url = "http://".$hash->{TCPIP}."/status?module=history_event"; + Log 1,"[DoorPi_GetHistory] called with only hash => Issue a non-blocking call to $url"; + HttpUtils_NonblockingGet({ + url => $url, + callback=>sub($$$){ DoorPi_GetHistory($hash,$_[1],$_[2]) } + }); + return undef; + }elsif ( $hash && $err1 && !$status1 && !$err2 && !$status2 ){ + Log 1,"[DoorPi_GetHistory] called with only hash and error $err1"; + return undef; + }elsif ( $hash && !$err1 && $status1 && !$err2 && !$status2 ){ + $url = "http://".$hash->{TCPIP}."/status?module=history_snapshot"; + Log 1,"[DoorPi_GetHistory] called with hash and data from first call => Issue a non-blocking call to $url"; + HttpUtils_NonblockingGet({ + url => $url, + callback=>sub($$$){ DoorPi_GetHistory($hash,$err1,$status1,$_[1],$_[2]) } + }); + return undef; + }elsif ( $hash && !$err1 && $status1 && $err2){ + Log 1,"[DoorPi_GetHistory] called with with hash and data from first call and second error $err2"; + return undef; + } + Log 1,"[DoorPi_GetHistory] has obtained data in two calls"; + + #-- crude test if this is valid JSON or some HTML page + if( substr($status1,0,1) eq "<" ){ + Log 1,"[DoorPi_GetHistory] but data from first call is invalid"; + return; + } + if( substr($status2,0,1) eq "<" ){ + Log 1,"[DoorPi_GetHistory] but data from second call is invalid"; + return; + } + + my $json = JSON->new->utf8; + my $jhash0 = $json->decode( $status1 ); + my $khash0 = $json->decode( $status2 ); + + #-- decode call history + my @history_event = @{$jhash0->{"history_event"}}; + my @history_snapshot = @{$khash0->{"history_snapshot"}}; + my $call = ""; + + #-- clear list of calls + @{$hash->{DATA}} = (); + + #-- going backward through the calls + my ($callend,$calletime,$calletarget,$callstime,$callstarget,$callsnap,$callrecord,$callstring); + for (my $i=0; $i<@history_event; $i++) { + my $event = $history_event[$i]; + + if( $event->{"event_name"} eq "OnCallStateChange" ){ + my $status1 = $event->{"additional_infos"}; + #-- workaround for bug in DoorPi + $status1 =~ tr/'/"/; + my $jhash1 = from_json( $status1 ); + my $call_state = $jhash1->{"call_state"}; + #-- end of call + if( ($call eq "") && (($call_state == 18) || ($call_state == 13)) ){ + $call = "active"; + $callrecord = ""; + $callend = $jhash1->{"state"}; + $callend =~ s/Call //; + if( $callend eq "released" ){ + #-- check previous 4 events + for( my $j=1; $j<5; $j++ ){ + if( $history_event[$i+$j]->{"event_name"} eq "OnCallStateChange"){ + my $status2 = $history_event[$i+$j]->{"additional_infos"}; + #-- workaround for bug in DoorPi + $status2 =~ tr/'/"/; + my $jhash2 = from_json( $status2 ); + if( $jhash2->{"state"} eq "Busy Here" ){ + $callend = "busy"; + last; + }elsif( $jhash2->{"state"} eq "Call ended" ){ + $callend = "OK"; + last; + } + } + } + }elsif( $callend eq "terminated" ){ + if( $history_event[$i-1]->{"event_name"} eq "OnSipPhoneCallTimeoutNoResponse"){ + $callend = "no response"; + } + } + $calletime = $event->{"start_time"}; + $calletarget = $jhash1->{"remote_uri"}; + }elsif( ($call eq "active") && ($call_state == 2) ){ + $call = ""; + $callstime = $event->{"start_time"}; + $callstarget = $jhash1->{"remote_uri"}; + #-- + if( $calletarget ne $callstarget){ + Log 1,"[DoorPi_GetHistory] Found error in call history of target $calletarget"; + }else{ + #-- Format values + my $state = ""; + my ($sec, $min, $hour, $day,$month,$year,$wday) = (localtime($callstime))[0,1,2,3,4,5,6]; + $year += 1900; + my $monthn = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")[$month]; + $wday = ("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa")[$wday]; + my $timestamp = sprintf("%s, %2d %s %d %02d:%02d:%02d", $wday,$day,$monthn,$year,$hour, $min, $sec); + my $number = $callstarget; + $number =~ s/sip://; + $number =~ s/\@.*//; + my $result = $callend; + my $duration = int(($calletime - $callstime)*10+0.5)/10; + + my $record = $callrecord; + $record =~ s/^.*records\///; + #-- workaround for buggy DoorPi + $record = sprintf("%d-%02d-%2d_%02d-%02d-%02d.wav", $year,($month+1),$day,$hour, $min, $sec) + if( $callend eq "OK"); + + #-- this is the snapshot file if taken at the same time + my $snapshot = sprintf("%d-%02d-%2d_%02d-%02d-%02d.jpg", $year,($month+1),$day,$hour, $min, $sec); + #-- check if it is present in the list of snapshots + my $found = 0; + for( my $i=0; $i<@history_snapshot; $i++){ + if( index($history_snapshot[$i],$snapshot) > -1){ + $found = 1; + last; + } + } + #-- if not, look for a file made a second later + if( $found == 0 ){ + ($sec, $min, $hour, $day,$month,$year,$wday) = (localtime($callstime+1))[0,1,2,3,4,5,6]; + $year += 1900; + $monthn = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")[$month]; + $wday = ("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa")[$wday]; + + #-- this is the snapshot file if taken at the same time + $snapshot = sprintf("%d-%02d-%2d_%02d-%02d-%02d.jpg", $year,($month+1),$day,$hour, $min, $sec); + #-- check if it is present in the list of snapshots + $found = 0; + for( my $i=0; $i<@history_snapshot; $i++){ + if( index($history_snapshot[$i],$snapshot) > -1){ + $found = 1; + last; + } + } + if( $found == 0 ){ + Log 1,"[DoorPi_GetHistory] No snapshot found with $snapshot"; + } + } + + #-- store this + push(@{ $hash->{DATA}}, [$state,$timestamp,$number,$result,$duration,$snapshot,$record] ); + } + } + } + #-- other events during call active + if( ($call eq "active") && ($event->{"event_name"} eq "OnRecorderStarted") ){ + my $status3 = $event->{"additional_infos"}; + $status3 =~ tr/'/"/; + my $jhash1 = from_json( $status3 ); + $callrecord = $jhash1->{"last_record_filename"}; + } + } + + #=================== Put into READINGS + readingsBeginUpdate($hash); + #readingsBulkUpdate($hash,"status_time",$jhash0->{"status_time"}); + readingsBulkUpdate($hash,"number_calls",int(@{ $hash->{DATA}})); + readingsEndUpdate($hash,1); + + return undef; +} + +######################################################################################## +# +# DoorPi_Cmd - Write command to DoorPi. Acting as callable routine and as callback +# +# Parameter hash, cmd = command +# +######################################################################################## + + sub DoorPi_Cmd () { + my ($hash, $cmd, $data) = @_; + my $name = $hash->{NAME}; + + my $url; + + if ( $hash && !$data){ + $url = "http://".$hash->{TCPIP}."/control/trigger_event?". + "event_name=OnKeyPressed_".$hash->{HELPER}->{vkeyboard}.".". + $cmd."&event_source=doorpi.keyboard.from_filesystem"; + Log 1,"[DoorPi_Cmd] called with only hash => Issue a non-blocking call to $url"; + HttpUtils_NonblockingGet({ + url => $url, + callback=>sub($$$){ DoorPi_Cmd($hash,$_[1],$_[2]) } + }); + return undef; + } + Log 1,"[DoorPi_Cmd] has obtained data"; + + #-- crude test if this is valid JSON or some HTML page + if( substr($data,0,1) eq "<" ){ + Log 1,"[DoorPi_Cmd] but data is invalid"; + return; + } + + my $json = JSON->new->utf8; + my $jhash = $json->decode( $data ); + my $msg = $jhash->{'message'}; + my $suc = $jhash->{'success'}; + if( $suc ){ + return $msg; + } + return undef; +} + +####################################################################################### +# +# DoorPi_maketable +# +# FW_detailFn & FW_summaryFn handler for creating the html output in FHEMWEB +# +####################################################################################### + +sub DoorPi_makeTable($$$$){ + my ($FW_wname, $devname, $room, $extPage) = @_; + my $hash = $defs{$devname}; + return DoorPi_list2html($hash) +} + +####################################################################################### +# +# DoorPi_list2html creating the call list as html string or json array +# +####################################################################################### + +sub DoorPi_list2html($;$){ + my ($hash, $to_json) = @_; + return undef if( !$hash ); + + my $name = $hash->{NAME}; + my $wwwpath = $hash->{HELPER}->{wwwpath}; + my $alias = AttrVal($hash->{NAME}, "alias", $hash->{NAME}); + my ($state,$timestamp,$number,$result,$duration,$snapshot,$record,$nrecord); + + my $td_style = 'style="padding-left:6px;padding-right:6px;"'; + my @json_output = (); + my $line; + + my $old_locale = setlocale(LC_ALL); + + if(AttrVal($name, "language", "en") eq "de"){ + setlocale(LC_ALL, "de_DE.utf8"); + }else{ + setlocale(LC_ALL, "en_US.utf8"); + } + + my $ret .= ""; + + if(AttrVal($name, "no-heading", "0") eq "0" and defined($FW_ME) and defined($FW_subdir)) + { + $ret .= ''; + } + + $ret .= "
'; + $ret .= '
'.$alias.''.(IsDisabled($name) ? ' (disabled)' : '').'
' + unless($FW_webArgs{"detail"}); + $ret .= '
"; + #-- div tag to support inform updates + $ret .= '
'; + if( exists($hash->{DATA}) && (int(@{$hash->{DATA}}) > 0) ){ + $ret .= ''; + + if(AttrVal($name, "language", "en") eq "de"){ + $state = "Wer"; + $timestamp = "Zeitpunkt"; + $number = "Rufnummer"; + $result = "Ergebnis"; + $duration = "Dauer"; + $record = "Aufzeichnung"; + }else{ + $state = "Who"; + $timestamp = "Timestamp"; + $number = "Number"; + $result = "Result"; + $duration = "Duration"; + $record = "Recording"; + } + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + + my @list = @{$hash->{DATA}}; + for(my $index=0; $index<(@list); $index++){ + my @data = @{$list[$index]}; + $state = $data[0]; + $timestamp = $data[1]; + $number = $data[2]; + $result = $data[3]; + $duration = $data[4]; + $snapshot = $data[5]; + $record = $data[6]; + + if(AttrVal($name, "language", "en") eq "de"){ + $result =~ s/busy/besetzt/; + $result =~ s/no\sresponse/ohne Antw./; + } + + if( $record ne ""){ + my $rs = $record; + $rs =~ s/.*$wwwpath\///; + $record = ''.$rs.''; + } + + if( $snapshot ne ""){ + $state = ''; + } + + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + } + $ret .= "
'.$state.''.$timestamp.''.$number.''.$result.''.$duration.''.$record.'
'.$state.''.$timestamp.''.$number.''.$result.''.$duration.''.$record.'
"; + }else{ + if(AttrVal($name, "language", "en") eq "de"){ + $ret .= "leer"; + }else{ + $ret .= "empty"; + } + } + + $ret .= "
"; + setlocale(LC_ALL, $old_locale); + + return ($ret); +} + + +1; + +=pod +=begin html + + +

DoorPi

+

FHEM module to communicate with a Raspberry Pi door station running DoorPi
+

Example


+

+ define DoorStation DoorPi 192.168.0.51 +
+


+ +

Define

+

+ define <name> DoorPi <IP address> +

Define a DoorpiPi instance.

+

+ +
+ +

Set

+ +
+ +

Get

+ +

Attributes

+ + +=end html +=cut + + + + + diff --git a/fhem/contrib/DoorPi/doorpi.ini.safe b/fhem/contrib/DoorPi/doorpi.ini.safe new file mode 100644 index 000000000..a75bbb8e0 --- /dev/null +++ b/fhem/contrib/DoorPi/doorpi.ini.safe @@ -0,0 +1,146 @@ +[DoorPi] +base_path = /usr/local/etc/DoorPi +snapshot_path = /home/doorpi/records +number_of_snapshots = 10 +eventlog = /home/doorpi/log/eventlog.db +is_alive_led = blinking_led +last_snapshot = + +[DoorPiWeb] +indexfile = index.html +loginfile = login.html +online_fallback = http://motom001.github.io/DoorPiWeb +port = 80 +public = AREA_public +www = /home/doorpi/records + + +[AREA_public] +.* + +[AREA_config] +/control/config_value_get +/control/config_value_set +/control/config_value_delete +/control/config_save +/control/config_get_configfile + +[AREA_dashboard] +/dashboard/pages/.*html + +[AREA_status] +/status +/mirror + +[AREA_control] +.* + +[User] +admin = admin +visitor = visitor + +[Group] +administrators = admin +guests = visitor + +[WritePermission] +administrators = dashboard,status,config + +[ReadPermission] +guests = dashboard + +[AdminNumbers] +**621 = active + +[EVENT_OnStartup] +10 = sleep:1 + +[EVENT_BeforeSipPhoneMakeCall] +10 = take_snapshot + +[SIP-Phone] +identity = DoorPi +local_port = 5060 +firewallpolicy = PolicyNoFirewall +# +sipphonetyp = linphone +sipserver_password = +sipserver_realm = fritz.box +sipserver_server = 192.168.0.254 +sipserver_username = 620 +stun_server = +# +max_call_time = 120 +call_timeout = 15 +ua.max_calls = 2 +# +capture_device = ALSA: USB PnP Sound Device +playback_device = ALSA: USB PnP Sound Device +audio_codecs = PCMA,PCMU +record_while_dialing = False +records = /home/doorpi/records/%Y-%m-%d_%H-%M-%S.wav +# +dialtone = /home/doorpi/sounds/ShortDialTone.wav +dialtone_renew_every_start = False +dialtone_volume = 35 +echo_cancellation_enabled = False +# +video_codecs = VP8 +video_device = StaticImage: Static picture +video_display_enabled = False +video_size = vga + +[keyboards] +onboardpins = piface +webservice = filesystem + +[webservice_keyboard] +base_path_input = /home/doorpi/keyboard/inputs/ +base_path_output = /home/doorpi/keyboard/outputs/ + +[webservice_InputPins] +door = out:door,1,0,3 +lighton = out:light +lightoff= out:light +purge = sleep:0 +clear = sleep:0 +button1 = sleep:0 +button2 = sleep:0 + +[EVENT_OnKeyPressed_webservice.purge] +10 = os_execute:/home/doorpi/purge.sh purge + +[EVENT_OnKeyPressed_webservice.clear] +10 = os_execute:/home/doorpi/purge.sh clear + +[EVENT_OnKeyPressed_webservice.button2] +10 = os_execute:/home/doorpi/test.sh + +[onboardpins_keyboard] +pull_up_down = PUD_UP + +[onboardpins_OutputPins] +0 = door +1 = light +2 = blinking_led + +[onboardpins_InputPins] +0 = call:722622 +1 = call:**621 +2 = file_call_value:/home/doorpi/callnumber +3 = take_snapshot +#--OK pin from Arduino +6 = sleep:0 +#-- NOK pin from Arduino +7 = sleep:0 + +[EVENT_OnKeyPressed_onboardpins.7] +10 = os_execute:/home/doorpi/iButton_NOK.sh + +[EVENT_OnKeyPressed_onboardpins.6] +10 = os_execute:/home/doorpi/iButton_OK.sh +20 = out:door,1,0,3 + +[DTMF] +"2" = out:door,1,0,3 + diff --git a/fhem/contrib/DoorPi/getparams.sh b/fhem/contrib/DoorPi/getparams.sh new file mode 100755 index 000000000..ac27315c2 --- /dev/null +++ b/fhem/contrib/DoorPi/getparams.sh @@ -0,0 +1,7 @@ +# ! /usr/bin/sh +# get FHEM values +callnumber='{ReadingsVal("A.Haus.T.Klingel","callnumber",0)}' +FHEM=`echo -e "$callnumber" | socat -t50 - TCP:192.168.0.90:7072` + +echo "$FHEM" > /var/DoorPi/callnumber + diff --git a/fhem/contrib/DoorPi/iButton_NOK.sh b/fhem/contrib/DoorPi/iButton_NOK.sh new file mode 100755 index 000000000..47e7942f6 --- /dev/null +++ b/fhem/contrib/DoorPi/iButton_NOK.sh @@ -0,0 +1,5 @@ +# ! /usr/bin/sh +curl "http://192.168.0.90:8085/fhem?XHR=1&cmd.GalaxyTab=set%20GalaxyTab%20ttsSay%20Unerlaubter%20Zutrittsversuch" + + + diff --git a/fhem/contrib/DoorPi/iButton_OK.sh b/fhem/contrib/DoorPi/iButton_OK.sh new file mode 100755 index 000000000..8bc7ea0fb --- /dev/null +++ b/fhem/contrib/DoorPi/iButton_OK.sh @@ -0,0 +1,6 @@ +# ! /usr/bin/sh +aplay -D plughw:1,0 /home/doorpi/sounds/067_willkommen.wav +curl "http://192.168.0.90:8085/fhem?XHR=1&cmd.GalaxyTab=set%20GalaxyTab%20ttsSay%20Ein%20Bewohner%20betritt%20das%20Haus" + + + diff --git a/fhem/contrib/DoorPi/purge.sh b/fhem/contrib/DoorPi/purge.sh new file mode 100755 index 000000000..ef7981a8c --- /dev/null +++ b/fhem/contrib/DoorPi/purge.sh @@ -0,0 +1,19 @@ +# ! /usr/bin/sh +action=$1 + +get_modify_time() +{ + stat $1 | grep -Po "Modify: \K[0-9- :]*" +} + + +if [ "$action" == "purge" ]; then + reference=/var/run/doorpi.pid + find records/ -type f ! -newer $reference -delete +elif [ "$action" == "clear" ]; then + echo "clear" + +else + echo "so what" +fi +