From c4b8e249f4871bad022ed937ad85666578bc4001 Mon Sep 17 00:00:00 2001
From: phenning
Date: Sat, 9 Dec 2017 18:16:42 +0000
Subject: [PATCH] 95_Alarm.pm: Neue Version mit diversen neuen Features
95_YAAHM.pm: Neue Version mit diversen neuen Features
git-svn-id: https://svn.fhem.de/fhem/trunk@15580 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/FHEM/95_Alarm.pm | 582 ++++++++++++++++++++++++++++++++---------
fhem/FHEM/95_YAAHM.pm | 144 ++++++----
fhem/www/pgm2/alarm.js | 316 ++++++++++++++++------
fhem/www/pgm2/yaahm.js | 56 ++++
4 files changed, 843 insertions(+), 255 deletions(-)
diff --git a/fhem/FHEM/95_Alarm.pm b/fhem/FHEM/95_Alarm.pm
index 8d0b8b715..b0b399116 100644
--- a/fhem/FHEM/95_Alarm.pm
+++ b/fhem/FHEM/95_Alarm.pm
@@ -35,13 +35,15 @@ use vars qw(%defs); # FHEM device/button definitions
use vars qw(%intAt); # FHEM at definitions
use vars qw($FW_ME);
+use JSON; # imports encode_json, decode_json, to_json and from_json.
+
#########################
# Global variables
my $alarmlinkname = "Alarms"; # link text
my $alarmhiddenroom = "AlarmRoom"; # hidden room
my $alarmpublicroom = "Alarm"; # public room
my $alarmno = 8;
-my $alarmversion = "3.0";
+my $alarmversion = "3.1";
my %alarm_transtable_EN = (
"ok" => "OK",
@@ -82,8 +84,11 @@ my %alarm_transtable_EN = (
"disarmaction" => "Disarm Action",
"waitaction" => "Wait Action",
"cancelaction" => "Cancel Action",
+ "canceled" => "canceled by:",
"alarm" => "Alarm",
+ "raised" => "raised by:",
"alarms" => "Alarm System",
+ "setparms" => "Set Parameters",
#--
"state" => "Security",
"unlocked" => "Unlocked",
@@ -133,8 +138,11 @@ my %alarm_transtable_EN = (
"disarmaction" => "Unscharf-Aktion",
"waitaction" => "Warte-Aktion",
"cancelaction" => "Widerruf-Aktion",
+ "canceled" => "widerrufen durch:",
"alarm" => "Alarm",
+ "raised" => "ausgelöst durch:",
"alarms" => "Alarmanlage",
+ "setparms" => "Parameter setzen",
#--
"state" => "Sicherheit",
"unlocked" => "Unverschlossen",
@@ -163,9 +171,10 @@ sub Alarm_Initialize ($) {
$hash->{GetFn} = "Alarm_Get";
$hash->{UndefFn} = "Alarm_Undef";
#$hash->{AttrFn} = "Alarm_Attr";
- my $attst = "lockstate:locked,unlocked testbutton:0,1 statedisplay:simple,color,table,none armdelay armwait armact disarmact cancelact";
+ my $attst = "lockstate:locked,unlocked testbutton:0,1 statedisplay:simple,color,table,none noicons iconmap disarmcolor ".
+ "armwaitcolor armcolor alarmcolor armdelay armwait armact disarmact cancelact";
for( my $level=0;$level<$alarmno;$level++ ){
- $attst .=" level".$level."start level".$level."end level".$level."msg level".$level."xec:0,1 level".$level."onact level".$level."offact ";
+ $attst .=" level".$level."start level".$level."end level".$level."msg level".$level."xec level".$level."onact level".$level."offact ";
}
$hash->{AttrList} = $attst;
@@ -181,7 +190,10 @@ sub Alarm_Initialize ($) {
$alarmlinkname = $alarm_tt->{"alarms"};
$data{FWEXT}{Alarmx}{LINK} = "?room=".$alarmhiddenroom;
- $data{FWEXT}{Alarmx}{NAME} = $alarmlinkname;
+ $data{FWEXT}{Alarmx}{NAME} = $alarmlinkname;
+
+ $data{FWEXT}{"/Alarm_widget"}{FUNC} = "Alarm_widget";
+ $data{FWEXT}{"/Alarm_widget"}{FORKABLE} = 0;
return undef;
}
@@ -215,6 +227,23 @@ sub Alarm_Define ($$) {
$data{FWEXT}{Alarmx}{LINK} = "?room=".$alarmhiddenroom;
$data{FWEXT}{Alarmx}{NAME} = $alarmlinkname;
$attr{$name}{"room"} = $alarmhiddenroom;
+
+ #$data{FWEXT}{"/Alarm_widget"}{FUNC} = "Alarm_widget";
+ #$data{FWEXT}{"/Alarm_widget"}{FORKABLE} = 0;
+
+ my $date = Alarm_restore($hash,0);
+ #-- data seems to be ok, restore
+ if( defined($date) ){
+ Alarm_restore($hash,1);
+ Log3 $name,1,"[Alarm_Define] data hash restored from save file with date $date";
+ #-- intialization
+ }else{
+ for( my $i=0;$i<$alarmno;$i++){
+ $hash->{DATA}{"armstate"}{"level".$i} = "disarmed";
+ }
+ Alarm_save($hash);
+ Log3 $name,1,"[Alarm_Define] data hash is initialized";
+ }
$modules{Alarm}{defptr}{$name} = $hash;
@@ -224,6 +253,24 @@ sub Alarm_Define ($$) {
return;
}
+sub Alarm_transform($){
+ my ($hash) = @_;
+
+ Log 1,"[Alarm] transforming old data format into new one";
+
+ my $md = 0;
+ for( my $i=0;$i<$alarmno;$i++){
+ if( defined(AttrVal($hash->{NAME},"level".$i."xec",undef)) ){
+ $md = 1;
+ $hash->{DATA}{"armstate"}{"level".$i} = AttrVal($hash->{NAME},"level".$i."xec","");
+ fhem("deleteattr ".$hash->{NAME}." level".$i."xec");
+ }
+ }
+ Alarm_save($hash)
+ if( $md==1 );
+}
+
+
#########################################################################################
#
# Alarm_Undef - Implements Undef function
@@ -302,19 +349,14 @@ sub Alarm_CreateEntry($) {
}
#-- recover state from stored readings
+ readingsBeginUpdate($hash);
for( my $level=0;$level<$alarmno;$level++ ){
- my $val = ReadingsVal($name,"level".$level,"");
- if( $val eq "disarmed" ){#
- CommandAttr (undef,$name.' level'.$level.'xec disarmed');
- }elsif( $val eq "armed" ){
- CommandAttr (undef,$name.' level'.$level.'xec armed');
- }else{
- Log3 $hash,1,"[Alarm $level] has undefined save data $val, disarming";
- CommandAttr (undef,$name.' level'.$level.'xec disarmed');
- }
+ my $val = $hash->{DATA}{"armstate"}{"level".$level};
+ readingsBulkUpdate( $hash, "level".$level, $val);
}
- my $mga = Alarm_getstate($hash)." Keine Störung";
- readingsSingleUpdate( $hash, "state", $mga, 1 );
+ my $mga = Alarm_getstate($hash);
+ readingsBulkUpdate( $hash, "state", $mga);
+ readingsEndUpdate( $hash,1 );
}
@@ -344,21 +386,31 @@ sub Alarm_Set($@) {
return "[Alarm] Invalid argument set $cmd";
}
return;
+ #-----------------------------------------------------------
} elsif ( $cmd =~ /^lock(ed)?$/ ) {
readingsSingleUpdate( $hash, "lockstate", "locked", 0 );
return;
+ #-----------------------------------------------------------
} elsif ( $cmd =~ /^unlock(ed)?$/ ) {
readingsSingleUpdate( $hash, "lockstate", "unlocked", 0 );
return;
+ #-----------------------------------------------------------
+ } elsif ( $cmd =~ /^save/ ) {
+ return Alarm_save($hash);
+
+ #-----------------------------------------------------------
+ } elsif ( $cmd =~ /^restore/ ) {
+ return Alarm_restore($hash,1);
+
} else {
my $str = join(",",(0..($alarmno-1)));
- return "[Alarm] Unknown argument " . $cmd . ", choose one of canceled:$str armed:$str disarmed:$str locked:noArg unlocked:noArg";
+ return "[Alarm] Unknown argument " . $cmd . ", choose one of canceled:$str armed:$str disarmed:$str locked:noArg unlocked:noArg save:noArg restore:noArg";
}
}
#########################################################################################
#
-# Alarm_Set - Implements the Get function
+# Alarm_Get - Implements the Get function
#
# Parameter hash = hash of device addressed
#
@@ -372,68 +424,10 @@ sub Alarm_Get($@) {
if ($arg eq "version") {
return "Alarm.version => $alarmversion";
} else {
- return "Unknown argument $arg choose one of version";
+ return "Unknown argument $arg choose one of version:noArg";
}
}
-#########################################################################################
-#
-# Alarm_getstate - Helper function to assemble a state display
-#
-# Parameter hash = hash of device addressed
-#
-#########################################################################################
-
-sub Alarm_getstate($) {
- my ($hash) = @_;
- my $res = '';
- my $type = AttrVal($hash->{NAME},"statedisplay",0);
- my $val;
- #--------------------------
- if( $type eq "simple" ){
- for( my $level=0;$level<$alarmno;$level++ ){
- $val = $hash->{READINGS}{"level".$level}{VAL};
- if( $val eq "disarmed" ){
- $res .= '-';
- }elsif( $val eq "armed" ){
- $res .= 'O';
- }else{
- $res .= 'X';
- }
- }
- #--------------------------
- }elsif( $type eq "color" ){
- $res = '';
- for( my $level=0;$level<$alarmno;$level++ ){
- $val = $hash->{READINGS}{"level".$level}{VAL};
- if( $val eq "disarmed" ){
- $res .= ' '.$level;
- }elsif( $val eq "armed" ){
- $res .= ' '.$level.' ';
- }else{
- $res .= ' '.$level.' ';
- }
- }
- $res.=' ';
- #--------------------------
- }elsif( $type eq "table" ){
- $res = '';
- for( my $level=0;$level<$alarmno;$level++ ){
- $val = $hash->{READINGS}{"level".$level}{VAL};
- if( $val eq "disarmed" ){
- $res .= ' ';
- }elsif( $val eq "armed" ){
- $res .= ' ';
- }else{
- $res .= ' ';
- }
- }
- $res.='
';
- #--------------------------
- }
- return $res;
-}
-
#########################################################################################
#
# Alarm_getsettings - Helper function to assemble the alarm settings for a device
@@ -462,8 +456,11 @@ sub Alarm_getsettings($$$){
$aval[3] = "";
$chg = 1;
}
- #--
- if( int(@aval) != 4){
+ #-- unset func may be missing
+ $aval[2] = ""
+ if(!defined($aval[2]));
+ #-- position 0:set by, 1:set func, 2:unset func, 3:delay
+ if( int(@aval) != 4 || !defined($aval[0]) || !defined($aval[1]) ){
Log3 $hash, 1, "[Alarm] Settings incomplete for alarmActor $dev";
}
}
@@ -474,6 +471,57 @@ sub Alarm_getsettings($$$){
return @aval;
}
+#########################################################################################
+#
+# Alarm_save
+#
+# Parameter hash = hash of the Alarm device
+#
+#########################################################################################
+
+sub Alarm_save($) {
+ my ($hash) = @_;
+ $hash->{DATA}{"savedate"} = localtime(time);
+ readingsSingleUpdate( $hash, "savedate", $hash->{DATA}{"savedate"}, 1 );
+ my $json = JSON->new->utf8;
+ my $jhash0 = eval{ $json->encode( $hash->{DATA} ) };
+ my $error = FileWrite("AlarmFILE",$jhash0);
+ #Log 1,"[Alarm_save] error=$error";
+ return;
+}
+
+#########################################################################################
+#
+# Alarm_restore
+#
+# Parameter hash = hash of the Alarm device
+#
+#########################################################################################
+
+sub Alarm_restore($$) {
+ my ($hash,$doit) = @_;
+ my $name = $hash->{NAME};
+ my ($error,$jhash0) = FileRead("AlarmFILE");
+ if( defined($error) && $error ne "" ){
+ Log3 $name,1,"[Alarm_restore] read error=$error";
+ return undef;
+ }
+ my $json = JSON->new->utf8;
+ my $jhash1 = eval{ $json->decode( $jhash0 ) };
+ my $date = $jhash1->{"savedate"};
+ #-- just for the first time, reading an old savefile
+ $date = localtime(time)
+ if( !defined($date));
+ readingsSingleUpdate( $hash, "savedate", $date, 0 );
+ if( $doit==1 ){
+ $hash->{DATA} = {%{$jhash1}};
+ Log3 $name,5,"[Alarm_restore] Data hash restored from save file with date ".$date;
+ return 1;
+ }else{
+ return $date;
+ }
+}
+
#########################################################################################
#
# Alarm_Test - Test an actor
@@ -514,8 +562,8 @@ sub Alarm_Exec($$$$$){
my ($name,$level,$dev,$evt,$act) = @_;
my $hash = $defs{$name};
- my $xec = AttrVal($name, "level".$level."xec", 0);
- my $xac = $hash->{READINGS}{'level'.$level}{VAL};
+ my $xec = $hash->{DATA}{"armstate"}{"level".$level};
+ my $xac = $hash->{READINGS}{"level".$level}{VAL};
my $msg = '';
my $cmd;
my $mga;
@@ -629,7 +677,7 @@ sub Alarm_Exec($$$$$){
readingsSingleUpdate( $hash, "level".$level,"canceled",1);
readingsSingleUpdate( $hash, "level".$level,"armed",1);
readingsSingleUpdate( $hash, "short", "", 0);
- $mga = Alarm_getstate($hash)." ".$mga;
+ $mga = Alarm_getstate($hash)." ".$alarm_tt->{"canceled"}." ".$dev;
readingsSingleUpdate( $hash, "state", $mga, 1 );
$msg = "[Alarm $level] canceled from device $dev";
Log3 $hash,3,$msg;
@@ -647,6 +695,7 @@ sub Alarm_Exec($$$$$){
# Parameter name = name of the Alarm definition
# level = Alarm level
# dev = name of the device calling the alarm
+# evt = Event of the device
# act = action - "armed" or "disarmed"
#
#########################################################################################
@@ -655,20 +704,26 @@ sub Alarm_Arm($$$$$){
my ($name,$level,$dev,$evt,$act) = @_;
my $hash = $defs{$name};
- my $xac = $hash->{READINGS}{"level"}{VAL};
- my $xec = AttrVal($name, 'level'.$level.'xec', 0);
+ my $xec = $hash->{DATA}{"armstate"}{"level".$level};
+ my $xac = $hash->{READINGS}{"level".$level}{VAL};
my $msg = '';
my $mga;
my $cmd;
#-- arming the alarm
- if( ($act eq "arm") && ( $xec ne "armed") ){
+ if( ($act eq "arm") && ( $xac ne "armed") ){
my $xdl = AttrVal($name, "armdelay", 0);
my $cmdwait = AttrVal($name, "armwait", 0);
my $cmdact = AttrVal($name, "armact", 0);
- if( ($xdl eq '')|($xdl eq '0:00')|($xdl eq '00:00') ){
- CommandAttr(undef,$name.' level'.$level.'xec armed');
+
+ #-- immediate arming
+ if( ($xdl eq '')||($xdl eq '0:00')||($xdl eq '00:00')||($evt eq "delay") ){
+ #-- update state display
+ $hash->{DATA}{"armstate"}{"level".$level} = "armed";
readingsSingleUpdate( $hash, "level".$level,"armed",1 );
+ readingsSingleUpdate( $hash, "state", Alarm_getstate($hash)." ".$hash->{READINGS}{"short"}{VAL}, 1 );
+ #-- save new state
+ Alarm_save($hash);
#--transform commands from fhem to perl level
my @cmdactarr = split(/;/,$cmdact);
my $cmdactf;
@@ -681,8 +736,14 @@ sub Alarm_Arm($$$$$){
}
$msg = "[Alarm $level] armed from alarmSensor $dev with event $evt";
Log3 $hash,3,$msg;
+
} elsif( $xdl =~ /([0-9])?:([0-5][0-9])?/ ){
- CommandAttr(undef,$name.' level'.$level.'xec armwait');
+ #-- update state display
+ $hash->{DATA}{"armstate"}{"level".$level} = "armed";
+ readingsSingleUpdate( $hash, "level".$level,"armwait",1 );
+ readingsSingleUpdate( $hash, "state", Alarm_getstate($hash)." ".$hash->{READINGS}{"short"}{VAL}, 1 );
+ #-- save new state
+ Alarm_save($hash);
#--transform commands from fhem to perl level
my @cmdactarr = split(/;/,$cmdact);
my $cmdactf;
@@ -694,30 +755,31 @@ sub Alarm_Arm($$$$$){
$cmdactf.="fhem(\"".$cmdactarr[$i]."\");;";
}
}
- #-- compose commands
- $cmd = sprintf("define alarm%1d.arm.dly at +00:%02d:%02d {fhem(\"setreading %s level%1d armed\");;fhem(\"attr %s level%1dxec armed\");;%s}",
- $level,$1,$2,$name,$level,$name,$level,$cmdactf);
+ #-- compose commands TODO
+ $cmd = sprintf("defmod alarm%1d.arm.dly at +00:%02d:%02d {Alarm_Arm(\"%s\",%1d,\"%s\",\"delay\",\"arm\");;%s}",
+ $level,$1,$2,$name,$level,$dev,$cmdactf);
$msg = "[Alarm $level] will be armed from alarmSensor $dev with event $evt, delay $xdl";
- #-- delete old delayed arm
- fhem('delete alarm'.$level.'.arm.dly' )
- if( defined $defs{'alarm'.$level.'.arm.dly'});
#-- define new delayed arm
fhem($cmd);
#-- execute armwait action
fhem($cmdwait);
- Log3 $hash,3,$msg;
+ Log3 $hash,1,$msg;
}else{
$msg = "[Alarm $level] cannot be armed due to wrong delay timespec";
Log3 $hash,1,$msg;
}
#-- disarming implies canceling as well
}elsif( ($act eq "disarm") && ($xec ne "disarmed")) {
- #-- delete old delayed arm
+ #-- delete stale delayed arm
fhem('delete alarm'.$level.'.arm.dly' )
if( defined $defs{'alarm'.$level.'.arm.dly'});
- CommandAttr (undef,$name.' level'.$level.'xec disarmed');
+ $hash->{DATA}{"armstate"}{"level".$level} = "disarmed";
Alarm_Exec($name,$level,"program","disarm","cancel");
+ #-- update state display
readingsSingleUpdate( $hash, "level".$level,"disarmed",1 );
+ readingsSingleUpdate( $hash, "state", Alarm_getstate($hash)." ".$hash->{READINGS}{"short"}{VAL}, 1 );
+ #-- save new state
+ Alarm_save($hash);
#--
$msg = "[Alarm $level] disarmed from alarmSensor $dev with event $evt";
$cmd = AttrVal($name, "disarmact", 0);
@@ -748,6 +810,9 @@ sub Alarm_CreateNotifiers($){
return "State locked, cannot create new notifiers";
}
+ #-- temporary code: transferm from attributes to hash
+ Alarm_transform($hash);
+
for( my $level=0;$level<$alarmno;$level++ ){
#-- delete old defs in any case
@@ -870,9 +935,9 @@ sub Alarm_CreateNotifiers($){
$nonum++;
my @tarr = split(':',$aval[3]);
if( int(@tarr) == 2){
- $cmd .= sprintf('define alarm%1ddly%1d at +00:%02d:%02d %s;',$level,$nonum,$tarr[0],$tarr[1],$aval[1]);
+ $cmd .= sprintf('defmod alarm%1ddly%1d at +00:%02d:%02d %s;',$level,$nonum,$tarr[0],$tarr[1],$aval[1]);
}elsif( int(@tarr) == 3){
- $cmd .= sprintf('define alarm%1ddly%1d at +%02d:%02d:%02d %s;',$level,$nonum,$tarr[0],$tarr[1],$tarr[2],$aval[1]);
+ $cmd .= sprintf('defmod alarm%1ddly%1d at +%02d:%02d:%02d %s;',$level,$nonum,$tarr[0],$tarr[1],$tarr[2],$aval[1]);
}else{
Log3 $name,1,"[Alarm $level] Invalid delay specification for actor $d, skipped";
$cmd .= $aval[1].';';
@@ -917,6 +982,183 @@ sub Alarm_CreateNotifiers($){
return "Created alarm notifiers";
}
+#########################################################################################
+#
+# Alarm_getstate - Helper function to assemble a state display
+#
+# Parameter hash = hash of device addressed
+#
+#########################################################################################
+
+sub Alarm_getstate($) {
+ my ($hash) = @_;
+
+ my $name = $hash->{NAME};
+ my $res = '';
+ my $type = AttrVal($hash->{NAME},"statedisplay",0);
+ my $val;
+ #--------------------------
+ if( $type eq "simple" ){
+ for( my $level=0;$level<$alarmno;$level++ ){
+ $val = $hash->{READINGS}{"level".$level}{VAL};
+ if( $val eq "disarmed" ){
+ $res .= '-';
+ }elsif( $val eq "armwait" ){
+ $res .= 'o';
+ }elsif( $val eq "armed" ){
+ $res .= 'O';
+ }else{
+ $res .= 'X';
+ }
+ }
+ #--------------------------
+ }else{
+
+ my $dac = AttrVal($name,"disarmcolor","lightgray");
+ my $ac = AttrVal($name,"armcolor","#53f3c7");
+ my $awc = AttrVal($name,"armwaitcolor","#ffe658");
+ my $alc = AttrVal($name,"alarmcolor","#fd5777");
+
+ if( $type eq "color" ){
+ $res = '';
+ for( my $level=0;$level<$alarmno;$level++ ){
+ $val = $hash->{READINGS}{"level".$level}{VAL};
+ if( $val eq "disarmed" ){
+ $res .= ' '.$level;
+ }elsif( $val eq "armwait" ){
+ $res .= ' '.$level.' ';
+ }elsif( $val eq "armed" ){
+ $res .= ' '.$level.' ';
+ }else{
+ $res .= ' '.$level.' ';
+ }
+ }
+ $res.=' ';
+ #--------------------------
+ }elsif( $type eq "table" ){
+ $res = '';
+ for( my $level=0;$level<$alarmno;$level++ ){
+ $val = $hash->{READINGS}{"level".$level}{VAL};
+ if( $val eq "disarmed" ){
+ $res .= ' ';
+ }elsif( $val eq "armwait" ){
+ $res .= ' ';
+ }elsif( $val eq "armed" ){
+ $res .= ' ';
+ }else{
+ $res .= ' ';
+ }
+ }
+ $res.='
';
+ }
+ }
+ return $res;
+}
+
+#########################################################################################
+#
+# Alarm_widget - returns animated SVG-code for the Alarm page
+#
+# Parameter name = name of the Alarm definition
+#
+#########################################################################################
+
+sub Alarm_widget($){
+ my ($arg) = @_;
+
+ my $name = $FW_webArgs{name};
+ my $sizep = $FW_webArgs{size};
+ my $gstate = ( $FW_webArgs{gstate} ? $FW_webArgs{gstate} : "disarmed");
+ my $dstate = ( $FW_webArgs{dstate} ? $FW_webArgs{dstate} : "--------");
+ my $inline = 0;
+
+ #-- no webarg, check direct parameter. TODO: order
+ if( !defined($name) || $name eq "" ){
+ if( $arg =~ /^name=(\w*)&gstate=(.+)&dstate=(.+)&size=(\d+x\d+)/ ){
+ $name = $1;
+ $gstate = $2;
+ $dstate = $3;
+ $sizep = $4;
+ $inline = 1;
+ }
+ }
+
+ Log 1,"[Alarm_widget] name=$name gstate=$gstate dstate=$dstate sizep=$sizep";
+
+ $name =~ s/'//g;
+ my @size=split('x',($sizep ? $sizep : '60x80'));
+
+ my ($fillcolor,$fillcolor2);
+ my $dac = AttrVal($name,"disarmcolor","lightgray");
+ my $ac = AttrVal($name,"armcolor","#53f3c7");
+ my $awc = AttrVal($name,"armwaitcolor","#ffe658");
+ my $alc = AttrVal($name,"alarmcolor","#fd5777");
+
+ if($gstate eq "disarmed"){
+ $fillcolor = AttrVal($name,"disarmcolor",$dac);
+ $fillcolor2 = "white";
+ }elsif($gstate eq "armed"){
+ $fillcolor = AttrVal($name,"armcolor",$ac);
+ $fillcolor2 = "white";
+ }elsif($gstate eq "mixed"){
+ $fillcolor = AttrVal($name,"armwaitcolor",$awc);
+ $fillcolor2 = "white";
+ }else{
+ $fillcolor = AttrVal($name,"alarmcolor",$alc);
+ $fillcolor2 = $fillcolor;
+ }
+
+ my $hash = $defs{$name};
+ my $id = $defs{$name}{NR};
+ my $ret="";
+
+ $ret = "";
+ $ret .= "".
+ "";
+ $ret .= "";
+ $ret .= " ";
+ $ret .= "";
+ for( my $level=0;$level<$alarmno;$level++ ){
+ my $val = $hash->{READINGS}{"level".$level}{VAL};
+ my $col;
+ if($val eq "disarmed"){
+ $col = $dac;
+ }elsif($val eq "armed"){
+ $col = $ac;
+ }elsif($val eq "armwait"){
+ $col = $awc;
+ }else{
+ $col = $alc;
+ }
+ $ret .= "";
+ }
+ $ret .= " ";
+
+ return $ret;
+
+ if( $inline ){
+ return $ret;
+ }else{
+ $FW_RETTYPE = "image/svg+xml";
+ $FW_RET="";
+ FW_pO $ret;
+ return ($FW_RETTYPE, $FW_RET);
+ }
+}
+
#########################################################################################
#
# Alarm_Html - returns HTML code for the Alarm page
@@ -944,7 +1186,7 @@ sub Alarm_Html($)
}
}
- #--
+ #-- update state display
readingsSingleUpdate( $hash, "state", Alarm_getstate($hash)." ".$hash->{READINGS}{"short"}{VAL}, 1 );
#--
@@ -954,30 +1196,92 @@ sub Alarm_Html($)
#--
$ret .= "\n";
$ret .= "\n";
- $ret .= " \n";
+ #--- here we insert the icon
+ $ret .= "";
+ $ret .= "".Alarm_widget("name=".$name."&gstate=".$iconstate."&dstate=".$detailstate."&size=60x80")."
"
+ if( AttrVal($name,"noicons",0)==0 );
+ $ret .= " ";
+ $ret .= " {"setparms"}."\" onclick=\"javascript:alarm_set('$name')\"/>".
+ "";
+ for( my $k=0;$k<$alarmno;$k++ ){
+ $ret .= "
".$hash->{READINGS}{"level".$k}{VAL}."
";
+ }
+ $ret .= "
\n";
#-- settings table
my $row=1;
- $ret .= "".$alarm_tt->{"settings"}."
";
- $ret .= "\n";
+ $ret .= "".$alarm_tt->{"settings"}."
";
+ $ret .= "\n";
$ret .= "\n";
- $ret .= "".$alarm_tt->{"armbutton"}." ↠ ";
+ $ret .= "".$alarm_tt->{"armbutton"}." ↠ ";
$ret .= " ".$alarm_tt->{"waitaction"}." ";
$ret .= sprintf(" ",(AttrVal($name, "armwait","") eq "1")?"":AttrVal($name, "armwait",""));
- $ret .= " ↴ ".$alarm_tt->{"delay"}." ↲";
+ $ret .= " ↴ ".$alarm_tt->{"delay"}." ↲";
$ret .= sprintf(" ",(AttrVal($name, "armdelay","0:00") eq "1")?"":AttrVal($name, "armdelay","0:00"));
$ret .= " \n";
$ret .= "".$alarm_tt->{"armaction"}." ";
@@ -985,7 +1289,7 @@ sub Alarm_Html($)
$ret .= " \n";
$ret .="".$alarm_tt->{"disarmbutton"}."↠ ".$alarm_tt->{"disarmaction"}." ";
$ret .= sprintf(" ",(AttrVal($name, "disarmact","") eq "1")?"":AttrVal($name, "disarmact",""));
- $ret .= " ".$alarm_tt->{"cancelbutton"}." ↠ ".$alarm_tt->{"cancelaction"}." ";
+ $ret .= " ".$alarm_tt->{"cancelbutton"}." ↠ ".$alarm_tt->{"cancelaction"}." ";
$ret .= sprintf(" ",(AttrVal($name, "cancelact","") eq "1")?"":AttrVal($name, "cancelact",""));
$ret .= "
";
$ret .= "".$alarm_tt->{"level"}." ".$alarm_tt->{"time"}." [hh:mm] ".
@@ -1004,6 +1308,7 @@ sub Alarm_Html($)
if( $mval eq "1");
my $xval = AttrVal($name, "level".$k."xec", 0);
+ my $xval = $hash->{DATA}{"armstate"}{"level".$k};
$ret .= sprintf(" ".$alarm_tt->{"alarm"}." $k \n", ($row&1)?"odd":"even");
$ret .= " ".
" ".
@@ -1011,12 +1316,12 @@ sub Alarm_Html($)
$ret .= sprintf(" ",($xval eq "armed")?"checked=\"checked\"":"").
" {"cancel"}."\" onclick=\"javascript:alarm_cancel('$name','$k')\"/> \n";
}
- $ret .= "
";
+ $ret .= "
";
#-- sensors table
$row=1;
- $ret .= "".$alarm_tt->{"sensors"}."
";
- $ret .= "\n";
+ $ret .= "".$alarm_tt->{"sensors"}."
";
+ $ret .= "\n";
$ret .= "".$alarm_tt->{"notifyto"}." ".$alarm_tt->{"alarm"}." ".$alarm_tt->{"level"}." ".
join(" ",(0..($alarmno-1)))." ".
$alarm_tt->{"notifyby"}." ".$alarm_tt->{"regexp"}." ".$alarm_tt->{"messagepart"}." I ".$alarm_tt->{"action"}." \n";
@@ -1042,12 +1347,12 @@ sub Alarm_Html($)
($aval[3] eq "arm")?"selected=\"seleced\"":"",($aval[3] eq "disarm")?"selected=\"selected\"":"");
}
}
- $ret .= "
";
+ $ret .= "
";
#-- actors table
$row=1;
- $ret .= "".$alarm_tt->{"actors"}."
";
- $ret .= "\n";
+ $ret .= "".$alarm_tt->{"actors"}."
";
+ $ret .= " \n";
+ $ret .= "
\n";
$ret .= "
";
@@ -1093,6 +1398,7 @@ sub Alarm_Html($)
Alarm
+
+ Notes:
+ This module uses the global attribute language to determine its output data
+ (default: EN=english). For German output set attr global language DE.
+ This module needs the JSON package.
+
Set
@@ -1122,6 +1433,10 @@ sub Alarm_Html($)
sets the lockstate of the alarm module to locked (i.e., alarm setups
may not be changed) resp. unlocked (i.e., alarm setups may be changed>)
+
+ set <name> save|restore
+
+ Manually save/restore the arm states to/from the external file AlarmFILE (save done automatically at each state modification, restore at FHEM start)
Get
@@ -1145,20 +1460,29 @@ sub Alarm_Html($)
locked|unlocked
locked means that alarm setups may not be changed, unlocked
means that alarm setups may be changed>
- attr <name> testbutton 0|1
+ attr <name> testbutton 0|1
1 means that a test button is displayed for every actor field
attr <name> statedisplay
simple,color,table,none
defines how the state of all eight alarm levels is shown. Example for the case
when alarm no. 0 is disarmed and only alarm no. 2 is raised:
- simple = -OXOOOOO
- color = 0 1 simple = OXOOOOO
+ color = 0 1 2 3 4 5 6 7
- table = HTML mini table with lightgray, green and red fields for alarms
+ table = HTML mini table with colored fields for alarms
none = no state display
+ attr <name> noicons
+ 0|1
+ when set to 1, animated icons are suppressed
+ attr <name> iconmap list
+ comma separated list of alarm levels for which the main icon/widget is set to disarmed/mixed/armed. No default=icon static
+ attr <name> disarmcolor|armwaitcolor|armcolor|alarmcolor color
+ four color specifications to signal the states disarmed (default lightgray ),
+ armwait (default #ffe658 ),
+ armed (default #53f3c7 ) and alarmed (default #fd5777 )
attr <name> armdelay mm:ss
time until the arming of an alarm becomes operative (0:00 - 9:59 allowed)
attr <name> armwait action
@@ -1172,7 +1496,7 @@ sub Alarm_Html($)
For each of the 8 alarm levels, several attributes
hold the alarm setup. They should not be changed by hand, but through the web
interface to avoid confusion: level<level>start, level<level>end,
- level<level>msg, level<level>xec, level<level>onact,
+ level<level>msg, level<level>onact,
level<level>offact
Standard attributes alias , comment , event-on-update-reading , room , eventMap , loglevel ,
webCmd
+
=end html
=begin html_DE
Alarm
+
=end html_DE
=cut
diff --git a/fhem/FHEM/95_YAAHM.pm b/fhem/FHEM/95_YAAHM.pm
index 353650494..0bbdfe601 100644
--- a/fhem/FHEM/95_YAAHM.pm
+++ b/fhem/FHEM/95_YAAHM.pm
@@ -6,8 +6,6 @@
#
# Prof. Dr. Peter A. Henning
#
-# TODO: Löschen readings, wenn timer gelöscht
-#
# $Id$
#
########################################################################################
@@ -50,7 +48,7 @@ my $yaahmname;
my $yaahmlinkname = "Profile"; # link text
my $yaahmhiddenroom = "ProfileRoom"; # hidden room
my $yaahmpublicroom = "Unsorted"; # public room
-my $yaahmversion = "1.30";
+my $yaahmversion = "1.31";
my $firstcall = 1;
my %yaahm_transtable_EN = (
@@ -328,14 +326,11 @@ my @profmode = ("party","absence","donotdisturb");
my @profday = ("vacation","holiday");
#-- color schemes
-my $csnum=2;
my @csmode;
my @csmode1 = ("#53f3c7","#8bfa56","#ff9458","#fd5777");
-my @csmode2 = ("#35ffc7","#77ff35","#ff7e35","#ff355e");
my @csstate;
my @csstate1 = ("#53f3c7","#ff9458","#f554e2","#fd5777");
-my @csstate2 = ("#35ffc7","#ff7e35","#ff35e2","#ff355e");
#-- temporary fix for update purpose
sub YAAHM_restore($$){};
@@ -358,7 +353,8 @@ sub YAAHM_Initialize ($) {
$hash->{UndefFn} = "YAAHM_Undef";
$hash->{AttrFn} = "YAAHM_Attr";
my $attst = "linkname publicroom hiddenroom lockstate:locked,unlocked simulation:0,1 ".
- "timeHelper modeHelper modeAuto:0,1 stateDevices:textField-long stateInterval noicons:0,1 colorscheme:1,2 stateWarning stateHelper stateAuto:0,1 ".
+ "modecolor0 modecolor1 modecolor2 modecolor3 statecolor0 statecolor1 statecolor2 statecolor3 ".
+ "timeHelper modeHelper modeAuto:0,1 stateDevices:textField-long stateInterval noicons:0,1 stateWarning stateHelper stateAuto:0,1 ".
"holidayDevices:textField-long vacationDevices:textField-long specialDevices:textField-long";
$hash->{AttrList} = $attst;
@@ -537,6 +533,32 @@ sub YAAHM_Attr($$$) {
}
}
#---------------------------------------
+ }elsif ( ($cmd eq "set") && ($attrName =~ /modecolor(\d)/) ) {
+ my $ci = $1;
+ if( $ci >= 0 && $ci <= 3 ){
+ $csmode[$ci] = $attrVal;
+ }
+
+ #---------------------------------------
+ }elsif ( ($cmd eq "del") && ($attrName =~ /modecolor(\d)/) ) {
+ my $ci = $1;
+ if( $ci >= 0 && $ci <= 3 ){
+ $csmode[$ci] = $csmode1[$ci];
+ }
+ #---------------------------------------
+ }elsif ( ($cmd eq "set") && ($attrName =~ /statecolor(\d)/) ) {
+ my $ci = $1;
+ if( $ci >= 0 && $ci <= 3 ){
+ $csstate[$ci] = $attrVal;
+ }
+
+ #---------------------------------------
+ }elsif ( ($cmd eq "del") && ($attrName =~ /statecolor(\d)/) ) {
+ my $ci = $1;
+ if( $ci >= 0 && $ci <= 3 ){
+ $csstate[$ci] = $csstate1[$ci];
+ }
+ #---------------------------------------
}elsif ( ($cmd eq "set") && ($attrName eq "linkname") ) {
$yaahmlinkname = $attrVal;
@@ -579,17 +601,7 @@ sub YAAHM_Attr($$$) {
}
}
}
- #---------------------------------------
- }elsif ( ($cmd eq "set") && ($attrName eq "colorscheme") ) {
- Log 1,"==================> colorscheme";
- if( $attrVal == 2 ){
- @csmode = @csmode2;
- @csstate = @csstate2;
- }else{
- @csmode = @csmode2;
- @csstate = @csstate2;
- }
-
+
#---------------------------------------
}elsif ( ($cmd eq "delete") && ($attrName eq "stateDevices") ) {
fhem("deletereading $name sdev_housestate");
@@ -713,6 +725,10 @@ sub YAAHM_Set($@) {
$cmd = "next_".$if;
}
return YAAHM_nextWeeklyTime($name,$cmd,$args[1],$exec);
+
+ #-----------------------------------------------------------
+ }elsif ( $cmd =~ /^checkstate.*/ ) {
+ YAAHM_InternalTimer("check",time()+ $args[0], "YAAHM_checkstate", $hash, 0);
#-----------------------------------------------------------
}elsif ( $cmd =~ /^time.*/ ) {
@@ -749,6 +765,7 @@ sub YAAHM_Set($@) {
$firstcall = 1;
YAAHM_updater($hash);
YAAHM_InternalTimer("check",time()+ 5, "YAAHM_checkstate", $hash, 0);
+
#-----------------------------------------------------------
} elsif ( $cmd eq "createWeekly" ){
return "[YAAHM] missing name for new weekly profile"
@@ -781,7 +798,7 @@ sub YAAHM_Set($@) {
#-- find index
$imax = int(@{$hash->{DATA}{"WT"}});
$if= undef;
- for( my $j=0;$j<$imax;$j++){
+ for( my $j=2;$j<$imax;$j++){
if($hash->{DATA}{"WT"}[$j]{"name"} eq $args[0]){
$if = $j;
last;
@@ -792,6 +809,25 @@ sub YAAHM_Set($@) {
splice(@{$hash->{DATA}{"WT"}},$if,1);
#-- delete timer
fhem("delete ".$name.".wtimer_".$if.".IF");
+ #-- delete readings
+ for( my $j=$if;$j<$imax-1;$j++){
+ $hash->{READINGS}{"ring_".$j}{VAL} = $hash->{READINGS}{"ring_".($j+1)}{VAL};
+ $hash->{READINGS}{"ring_".$j."_1"}{VAL} = $hash->{READINGS}{"ring_".($j+1)."_1"}{VAL};
+ $hash->{READINGS}{"next_".$j}{VAL} = $hash->{READINGS}{"next_".($j+1)}{VAL};
+ $hash->{READINGS}{"today_".$j}{VAL} = $hash->{READINGS}{"today_".($j+1)}{VAL};
+ $hash->{READINGS}{"today_".$j."_e"}{VAL} = $hash->{READINGS}{"today_".($j+1)."_e"}{VAL};
+ $hash->{READINGS}{"tomorrow_".$j}{VAL} = $hash->{READINGS}{"tomorrow_".($j+1)}{VAL};
+ $hash->{READINGS}{"tomorrow_".$j."_e"}{VAL} = $hash->{READINGS}{"tomorrow_".($j+1)."_e"}{VAL};
+ $hash->{READINGS}{"tr_wake_".$j}{VAL} = $hash->{READINGS}{"tr_wake".($j+1)}{VAL};
+ }
+ fhem("deletereading ".$name." ring_".($imax-1));
+ fhem("deletereading ".$name." ring_".($imax-1)."_1");
+ fhem("deletereading ".$name." next_".($imax-1));
+ fhem("deletereading ".$name." today_".($imax-1));
+ fhem("deletereading ".$name." today_".($imax-1)."_e");
+ fhem("deletereading ".$name." tomorrow_".($imax-1));
+ fhem("deletereading ".$name." tomorrow_".($imax-1)."_e");
+ fhem("deletereading ".$name." tr_wake_".($imax-1));
#-- save everything
YAAHM_save($hash);
fhem("save");
@@ -802,7 +838,7 @@ sub YAAHM_Set($@) {
my $str = "";
return "[YAAHM] Unknown argument " . $cmd . ", choose one of".
" manualnext time:".join(',',@times)." mode:".join(',',@modes).
- " state:".join(',',@states)." locked:noArg unlocked:noArg save:noArg restore:noArg initialize:noArg createWeekly deleteWeekly";
+ " state:".join(',',@states)." locked:noArg unlocked:noArg save:noArg checkstate:0,5,10 restore:noArg initialize:noArg createWeekly deleteWeekly";
}
}
@@ -1424,19 +1460,6 @@ sub YAAHM_checkstate($) {
return undef
}
-#########################################################################################
-#
-# YAAHM_SM - State machine
-#
-# Parameter hash = hash of device addressed
-#
-#########################################################################################
-
-sub YAAHM_SM($) {
- my ($hash) = @_;
-
-}
-
#########################################################################################
#
# YAAHM_informer - Tell FHEMWEB to inform this page
@@ -1721,6 +1744,9 @@ sub YAAHM_setWeeklyTime($) {
#-- today's waketime
my $tga = $sg0;
$tga =~ s/://;
+ #-- tomorrow's waketime
+ my $tgm = $sg1;
+ $tgm =~ s/://;
#-- "next" input
my $nga = (defined $ng)?$ng:"";
$nga =~ s/://;
@@ -1729,6 +1755,20 @@ sub YAAHM_setWeeklyTime($) {
if( $nga eq "" ){
$ring_0 = $sg0;
$ring_1 = $sg1;
+ $ng = "";
+ $hash->{DATA}{"WT"}[$i]{ "next" }="";
+ #-- "next" is the same as today and today not over
+ }elsif( ($nga eq $tga) && ($tga > $lga)){
+ $ring_0 = $sg0;
+ $ring_1 = $sg1;
+ $ng = "";
+ $hash->{DATA}{"WT"}[$i]{ "next" }="";
+ #-- "next" is the same as tomorrow and today over
+ }elsif( ($nga eq $tgm) && ($tga < $lga)){
+ $ring_0 = $sg0;
+ $ring_1 = $sg1;
+ $ng = "";
+ $hash->{DATA}{"WT"}[$i]{ "next" }="";
#-- "next" is off
}elsif( $nga eq "off" ){
#-- today's waketime not over => we mean today
@@ -1750,10 +1790,11 @@ sub YAAHM_setWeeklyTime($) {
}else{
#-- "next" after current time => we mean today
if( $nga > $lga ){
- #-- only restore standard setting
+ #-- only restore standard setting (do we come here at all ?)
if( $ng eq $sg0 ){
$sg0mod = $sg0;
$ring_0 = $sg0;
+ $ng = "";
$hash->{DATA}{"WT"}[$i]{ "next" } = "";
}else{
$sg0mod = "$ng (man)";
@@ -1762,10 +1803,11 @@ sub YAAHM_setWeeklyTime($) {
$ring_1 = $sg1;
#-- "next" before current time => we mean tomorrow
}else{
- #-- only restore standard setting
+ #-- only restore standard setting (do we come here at all ?)
if( $ng eq $sg1 ){
$sg0mod = $sg1;
$ring_1 = $sg1;
+ $ng = "";
$hash->{DATA}{"WT"}[$i]{ "next" } = "";
}else{
$sg1mod = "$ng (man)";
@@ -2980,7 +3022,7 @@ sub YAAHM_timewidget($){
FW_pO ' ';
#-- evening to sunset sector
- $dir = ( $ss < $ev ) ? 1 : 0;
+ $dir = ( $ss < $ev ) ? 0 : 1;
FW_pO ' ';
#-- midnight line
@@ -3070,6 +3112,9 @@ sub YAAHM_toptable($){
$ret .= "var csmode = [\"".$csmode[0]."\",\"".$csmode[1]."\",\"".$csmode[2]."\",\"".$csmode[3]."\"];";
$ret .= "var csstate = [\"".$csstate[0]."\",\"".$csstate[1]."\",\"".$csstate[2]."\",\"".$csstate[3]."\"];";
+ $ret .= "var blinking = 0;\n";
+ $ret .= "var hscolor = \"".$csstate[0]."\";\n";
+
$ret .= "var dailyno = ".$dailyno.";\n";
$ret .= "var dailykeys = [\"".join("\",\"",(sort YAAHM_dsort keys %dailytable))."\"];\n";
@@ -3080,9 +3125,14 @@ sub YAAHM_toptable($){
$ret .= ","
if( $i!=0 );
$ret .= "\"".$hash->{DATA}{"WT"}[$i]{"name"}."\"";
- }
+ }
$ret .= "];\n";
+ #-- watcher for next hidden divisions
+ for( my $i=2;$i<$weeklyno;$i++){
+ $ret .= "$(\"body\").on('DOMSubtreeModified', \"#wt".$i."_o\",function () {nval = document.getElementById(\"wt".$i."_o\").innerHTML;document.getElementById(\"wt".$i."_n\").value = nval;})\n";
+ }
$ret .= "\n";
+
$ret .= "".ReadingsVal($name,"housestate",undef)."
".
"".ReadingsVal($name,"housemode",undef)."
";
$ret .= "\n";
@@ -3108,7 +3158,7 @@ sub YAAHM_toptable($){
$ret .= "".YAAHM_statewidget($hash)." ".
"".$yaahm_tt->{"state"}." ".
"".ReadingsVal($name,"tr_housestate",undef).
- "
".ReadingsVal($name,"sym_housestate",undef)."
";
+ "".ReadingsVal($name,"sym_housestate",undef)."
";
for( my $i=0; $i<$cols; $i++){
if( $i < int(@states)){
$ret .= " {$states[$i]}.
@@ -3124,7 +3174,7 @@ sub YAAHM_toptable($){
#-- repeat manual next for every weekly table
my $nval = "";
my $wupn;
- $ret .= "".$yaahm_tt->{"manual"}." ";
+ $ret .= "".$yaahm_tt->{"manual"}." \n";
for (my $i=0;$i<$weeklyno;$i++){
if($i<$weeklyno-1){
$styl= "border-bottom:1px solid gray;border-top:1px solid gray";
@@ -3134,7 +3184,7 @@ sub YAAHM_toptable($){
$wupn = $hash->{DATA}{"WT"}[$i]{"name"};
$nval = ( defined($hash->{DATA}{"WT"}[$i]{"next"}) ) ? $hash->{DATA}{"WT"}[$i]{"next"} : "";
$ret .= sprintf("$wupn ".
- " ",$i,$i);
+ "$nval
\n",$i,$i,$i);
}
$ret .= " \n";
$ret .= "
";
@@ -3546,6 +3596,7 @@ sub YAAHM_Longtable($){
Notes:
This module uses the global attribute language to determine its output data
(default: EN=english). For German output set attr global language DE.
+ This module needs the JSON package
Set
@@ -3619,7 +3670,7 @@ sub YAAHM_Longtable($){
set <name> save|restore
- Manually save/restore the complete profile data to/from the external file YAAHMFILE (save done automatically at each timer starte, restore at FHEM start)
+ Manually save/restore the complete profile data to/from the external file YAAHMFILE (save done automatically at each timer start, restore at FHEM start)
Get
@@ -3661,9 +3712,14 @@ sub YAAHM_Longtable($){
attr <name> noicons
0|1
when set to 1, animated icons are suppressed
- attr <name> colorscheme
- 1|2
- color scheme for the icons
+ attr <name> modecolor[0|1|2|3] color
+ four color specifications to signal the modes normal (default #53f3c7 ),
+ party (default #8bfa56 ), absence (default #ff9458 ),
+ donotodisturb (default #fd5777 ),
+ attr <name> statecolor[0|1|2|3] color
+ four color specifications to signal the states unsecured (default #53f3c7 ),
+ secured (default #ff9458 ),
+ protected (default #f554e2 ) and guarded (default #fd5777 )
attr <name> timeHelper <name of perl program>
name of a perl function that is called at each time step of the daily profile and for the two default weekly profiles
attr <name> modeHelper <name of perl program>
diff --git a/fhem/www/pgm2/alarm.js b/fhem/www/pgm2/alarm.js
index cd71bf6fa..4de207149 100644
--- a/fhem/www/pgm2/alarm.js
+++ b/fhem/www/pgm2/alarm.js
@@ -1,10 +1,10 @@
//########################################################################################
// alarm.js
-// Version 2.81
+// Version 3.1
// See 95_Alarm for licensing
//########################################################################################
//# Prof. Dr. Peter A. Henning
-
+
function encodeParm(oldval) {
var newval;
newval = oldval.replace(/\+/g, '%2B');
@@ -13,134 +13,284 @@ function encodeParm(oldval) {
return newval;
}
-//var ah = new HashTable('l0s','','l0e','');
+//------------------------------------------------------------------------------------------------------
+// Animated Icon
+//------------------------------------------------------------------------------------------------------
+
+var bellfill;
+
+function blinkbell() {
+ var w = document.getElementById("alarmicon");
+ if (w) {
+ if (bellfill == alarmcolor) {
+ bellfill = "white";
+ w.getElementsByClassName("alarmst_b")[0].setAttribute("fill", "white");
+ w.getElementsByClassName("alarmst_sb")[0].setAttribute("fill", "white");
+ } else {
+ bellfill = alarmcolor;
+ w.getElementsByClassName("alarmst_b")[0].setAttribute("fill", alarmcolor);
+ w.getElementsByClassName("alarmst_sb")[0].setAttribute("fill", alarmcolor);
+ }
+ }
+}
+
+function updateIcon(name, alarmst) {
+ var w = document.getElementById(name);
+ if (w) {
+ switch (alarmst) {
+ case "disarmed":
+ w.getElementsByClassName("alarmst_b")[0].setAttribute("fill", "white");
+ w.getElementsByClassName("alarmst_sb")[0].setAttribute("fill", "white");
+ if (blinking == 1) {
+ clearInterval(blinker);
+ blinking = 0;
+ }
+ break;
+
+ case "mixed":
+ w.getElementsByClassName("alarmst_b")[0].setAttribute("fill", armwaitcolor);
+ w.getElementsByClassName("alarmst_sb")[0].setAttribute("fill", "white");
+ if (blinking == 1) {
+ clearInterval(blinker);
+ blinking = 0;
+ }
+ break;
+
+ case "armed":
+ w.getElementsByClassName("alarmst_b")[0].setAttribute("fill", armcolor);
+ w.getElementsByClassName("alarmst_sb")[0].setAttribute("fill", "white");
+ if (blinking == 1) {
+ clearInterval(blinker);
+ blinking = 0;
+ }
+ break;
+
+ default:
+ if (blinking == 0) {
+ blinker = setInterval('blinkbell()', 250);
+ blinking = 1;
+ }
+ }
+ }
+}
+
+$("body").on('DOMSubtreeModified', "#hid_levels", function () {
+ var w = document.getElementById("hid_levels");
+ var v = document.getElementById("alarmicon");
+ var t = v.getElementsByClassName("arec");
+ var ifnd;
+ var sfnd;
+ var col;
+ for (i = 0; i < alarmno; i++) {
+ var s = w.getElementsByClassName("hid_lx")[i].innerHTML;
+ if (ast[i] != s) {
+ switch(s){
+ case "disarmed":
+ col = disarmcolor;
+ break;
+ case "armwait":
+ col = armwaitcolor;
+ break;
+ case "armed":
+ col = armcolor;
+ break;
+ default:
+ col = alarmcolor
+ }
+ t[i].setAttribute("fill",col);
+ ast[i] = s;
+ ifnd = i;
+ sfnd = s;
+ }
+ }
+ if (ifnd && (iconmap.includes(ifnd))) {
+ var aan = true;
+ var adn = true;
+ var aln = "";
+ var atn = "";
+ for (i = 0; i < alarmno; i++) {
+ if (iconmap.includes(i)) {
+ var s = ast[i];
+ if (s != "disarmed" && s != "armwait" && s != "armed") {
+ aln = aln + i + ",";
+ atn = atn + s + ",";
+ } else {
+ adn = adn && ((s == "disarmed")||(s == "armwait"));
+ aan = aan && (s == "armed");
+ }
+ }
+ }
+
+ if (adn != ad || aan != aa || aln != al) {
+ aa = aan;
+ ad = adn;
+ al = aln;
+ at = atn;
+
+ var iconstate;
+ if (al != "") {
+ iconstate = al;
+ } else {
+ if (aa && (! ad)) {
+ iconstate = "armed";
+ } else {
+ if ((! aa) && ad) {
+ iconstate = "disarmed";
+ } else {
+ iconstate = "mixed";
+ }
+ }
+ }
+ updateIcon('alarmicon', iconstate);
+ }
+ }
+});
//------------------------------------------------------------------------------------------------------
// Write the Attribute Value
//------------------------------------------------------------------------------------------------------
-function alarm_setAttribute(name, attr, val) {//set Alarm Attribute
- var location = document.location.pathname;
- if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);}
- var url = document.location.protocol+"//"+document.location.host+location;
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' '+encodeParm(attr)+' '+ encodeParm(val));
+
+function alarm_setAttribute(name, attr, val) {
+ //set Alarm Attribute
+ var location = document.location.pathname;
+ if (location.substr(location.length -1, 1) == '/') {
+ location = location.substr(0, location.length -1);
+ }
+ var url = document.location.protocol + "//" + document.location.host + location;
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' ' + encodeParm(attr) + ' ' + encodeParm(val));
}
-function alarm_cancel(name,level){
+function alarm_cancel(name, level) {
var val;
var nam;
-
+
var location = document.location.pathname;
- if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);}
- var url = document.location.protocol+"//"+document.location.host+location;
+ if (location.substr(location.length -1, 1) == '/') {
+ location = location.substr(0, location.length -1);
+ }
+ var url = document.location.protocol + "//" + document.location.host + location;
+
+ FW_cmd(url + '?XHR=1&cmd.' + name + '={Alarm_Exec("' + name + '",' + level + ',"web","button","off")}');
+}
- FW_cmd(url+'?XHR=1&cmd.'+name+'={Alarm_Exec("'+name+'",'+level+',"web","button","off")}');
- }
-
-function alarm_arm(name,level){
+function alarm_arm(name, level) {
var val;
var nam;
- var command = document.getElementById('l'+level+'x').checked;
- if (command == true){
- command="arm";
- }else{
- command="disarm";
+ var command = document.getElementById('l' + level + 'x').checked;
+ if (command == true) {
+ command = "arm";
+ } else {
+ command = "disarm";
}
var location = document.location.pathname;
- if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);}
- var url = document.location.protocol+"//"+document.location.host+location;
+ if (location.substr(location.length -1, 1) == '/') {
+ location = location.substr(0, location.length -1);
+ }
+ var url = document.location.protocol + "//" + document.location.host + location;
+
+ FW_cmd(url + '?XHR=1&cmd.' + name + '={Alarm_Arm("' + name + '",' + level + ',"web","button","' + command + '")}');
+}
- FW_cmd(url+'?XHR=1&cmd.'+name+'={Alarm_Arm("'+name+'",'+level+',"web","button","'+command+'")}');
- }
-
-function alarm_testaction(name,dev,type){
+function alarm_testaction(name, dev, type) {
var cmd;
var nam;
- if(type == 'set'){
- cmd = document.getElementById(dev).parentElement.children[2].children[0].value;
- }else{
- cmd = document.getElementById(dev).parentElement.children[3].children[0].value;
+ if (type == 'set') {
+ cmd = document.getElementById(dev).parentElement.children[2].children[0].value;
+ } else {
+ cmd = document.getElementById(dev).parentElement.children[3].children[0].value;
}
var cmds;
cmds = cmd.replace(/\\/g, '\\');
cmds = cmds.replace(/\'/g, '\"');
cmds = cmds.replace(/\$/g, '\\$');
- alert( cmds );
-
- var location = document.location.pathname;
- if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);}
- var url = document.location.protocol+"//"+document.location.host+location;
-
- FW_cmd(url+'?XHR=1&cmd.'+name+'={Alarm_Test("'+name+'","' + cmds + '")}');
- }
+ alert(cmds);
+ var location = document.location.pathname;
+ if (location.substr(location.length -1, 1) == '/') {
+ location = location.substr(0, location.length -1);
+ }
+ var url = document.location.protocol + "//" + document.location.host + location;
+
+ FW_cmd(url + '?XHR=1&cmd.' + name + '={Alarm_Test("' + name + '","' + cmds + '")}');
+}
-function alarm_set(name){
+
+function alarm_set(name) {
var val;
var nam;
-
+
var location = document.location.pathname;
- if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);}
- var url = document.location.protocol+"//"+document.location.host+location;
+ if (location.substr(location.length -1, 1) == '/') {
+ location = location.substr(0, location.length -1);
+ }
+ var url = document.location.protocol + "//" + document.location.host + location;
// saving arm data
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' armdelay '+ document.getElementById('armdelay').value);
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' armwait '+ encodeParm(document.getElementById('armwait').value));
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' armact '+ encodeParm(document.getElementById('armaction').value));
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' disarmact '+ encodeParm(document.getElementById('disarmaction').value));
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' cancelact '+ encodeParm(document.getElementById('cancelaction').value));
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' armdelay ' + document.getElementById('armdelay').value);
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' armwait ' + encodeParm(document.getElementById('armwait').value));
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' armact ' + encodeParm(document.getElementById('armaction').value));
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' disarmact ' + encodeParm(document.getElementById('disarmaction').value));
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' cancelact ' + encodeParm(document.getElementById('cancelaction').value));
// saving start and end times
- for (var i = 0; i < alarmno; i++){
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' level'+i+'start '+document.getElementById('l'+i+'s').value);
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' level'+i+'end ' +document.getElementById('l'+i+'e').value);
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' level'+i+'msg ' +document.getElementById('l'+i+'m').value);
- if (document.getElementById('l'+i+'x').checked == true ){
+ for (var i = 0;
+ i < alarmno;
+ i++) {
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'start ' + document.getElementById('l' + i + 's').value);
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'end ' + document.getElementById('l' + i + 'e').value);
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'msg ' + document.getElementById('l' + i + 'm').value);
+ if (document.getElementById('l' + i + 'x').checked == true) {
val = "armed";
- }else{
+ } else {
val = "disarmed";
}
- FW_cmd(url+'?XHR=1&cmd.'+name+'=attr '+name+' level'+i+'xec ' + val);
- }
+ FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'xec ' + val);
+ }
//for (var k in ah.items) {
// ah.setItem(k,document.getElementById(k).value);
//}
// acquiring data for each sensor
- var sarr = document.getElementsByName('sensor');
- for (var k = 0; k < sarr.length; k++){
- nam = sarr[k].getAttribute('informId');
- val = "";
- for (var i = 0; i < alarmno; i++){
- if (sarr[k].children[1].children[i].checked == true ){
- val += "alarm"+i+",";
+ var sarr = document.getElementsByName('sensor');
+ for (var k = 0;
+ k < sarr.length;
+ k++) {
+ nam = sarr[k].getAttribute('informId');
+ val = "";
+ for (var i = 0;
+ i < alarmno;
+ i++) {
+ if (sarr[k].children[1].children[i].checked == true) {
+ val += "alarm" + i + ",";
}
}
- val += "|"+sarr[k].children[2].children[0].value;
- val += "|"+sarr[k].children[3].children[0].value;
- val += "|"+sarr[k].children[4].children[0].options[sarr[k].children[4].children[0].selectedIndex].value;
- FW_cmd(url+'?XHR=1&cmd.'+nam+'=attr '+nam+' alarmSettings ' + encodeParm(val));
+ val += "|" + sarr[k].children[2].children[0].value;
+ val += "|" + sarr[k].children[3].children[0].value;
+ val += "|" + sarr[k].children[4].children[0].options[sarr[k].children[4].children[0].selectedIndex].value;
+ FW_cmd(url + '?XHR=1&cmd.' + nam + '=attr ' + nam + ' alarmSettings ' + encodeParm(val));
}
// acquiring data for each actor
- var aarr = document.getElementsByName('actor');
- for (var k = 0; k < aarr.length; k++){
- nam = aarr[k].getAttribute('informId');
- val = "";
- for (var i = 0; i < alarmno; i++){
+ var aarr = document.getElementsByName('actor');
+ for (var k = 0;
+ k < aarr.length;
+ k++) {
+ nam = aarr[k].getAttribute('informId');
+ val = "";
+ for (var i = 0;
+ i < alarmno;
+ i++) {
//alert(" Checking "+k+" "+i)
- if (aarr[k].children[1].children[i].checked == true ){
- val += "alarm"+i+",";
+ if (aarr[k].children[1].children[i].checked == true) {
+ val += "alarm" + i + ",";
}
}
- val += "|"+aarr[k].children[2].children[0].value;
- val += "|"+aarr[k].children[3].children[0].value;
- val += "|"+aarr[k].children[4].children[0].value;
- FW_cmd(url+'?XHR=1&cmd.'+nam+'=attr '+nam+' alarmSettings ' + encodeParm(val));
+ val += "|" + aarr[k].children[2].children[0].value;
+ val += "|" + aarr[k].children[3].children[0].value;
+ val += "|" + aarr[k].children[4].children[0].value;
+ FW_cmd(url + '?XHR=1&cmd.' + nam + '=attr ' + nam + ' alarmSettings ' + encodeParm(val));
}
// creating notifiers
- FW_cmd(url+'?XHR=1&cmd.' + name + ' ={main::Alarm_CreateNotifiers("' + name + '")}');
-
-}
-
-
+ FW_cmd(url + '?XHR=1&cmd.' + name + ' ={main::Alarm_CreateNotifiers("' + name + '")}');
+}
\ No newline at end of file
diff --git a/fhem/www/pgm2/yaahm.js b/fhem/www/pgm2/yaahm.js
index 58682e45a..1c5b31462 100644
--- a/fhem/www/pgm2/yaahm.js
+++ b/fhem/www/pgm2/yaahm.js
@@ -98,10 +98,62 @@ function yaahm_setnext(name, i) {
FW_cmd(url + '?XHR=1&cmd.' + name + '={main::YAAHM_nextWeeklyTime("' + name + '","next_' + i + '","' + nval + '")}');
}
+//------------------------------------------------------------------------------------------------------
+// Write field value for next - first two here, the others dynamically
+//------------------------------------------------------------------------------------------------------
+
+$("body").on('DOMSubtreeModified', "#wt0_o",
+ function () {
+ nval = document.getElementById("wt0_o").innerHTML;
+ document.getElementById("wt0_n").value = nval;
+ })
+
+$("body").on('DOMSubtreeModified', "#wt1_o",
+ function () {
+ nval = document.getElementById("wt1_o").innerHTML;
+ document.getElementById("wt1_n").value = nval;
+ })
+
//------------------------------------------------------------------------------------------------------
// Animate housestate icon
//------------------------------------------------------------------------------------------------------
+var blinker;
+var hsfill;
+var hscolor;
+
+function blinkhs() {
+ var w = document.getElementById("wid_hs");
+ if (w) {
+ if (hsfill == hscolor) {
+ hsfill = "white";
+ w.getElementsByClassName("hs_is")[0].setAttribute("fill", "white");
+ } else {
+ hsfill = hscolor;
+ w.getElementsByClassName("hs_is")[0].setAttribute("fill", hscolor);
+ }
+ }
+}
+
+$("body").on('DOMSubtreeModified', "#sym_hs",
+function () {
+ var w = document.getElementById("wid_hs");
+ if (w) {
+ var symnew = document.getElementById("sym_hs").innerHTML;
+ if (blinking == 1 && symnew.includes("green")) {
+ clearInterval(blinker);
+ blinking = 0;
+ w.getElementsByClassName("hs_is")[0].setAttribute("fill", hscolor);
+ } else {
+ if (blinking == 0 && ! symnew.includes("green")) {
+ hscolor = w.getElementsByClassName("hs_is")[0].getAttribute("fill");
+ blinker = setInterval('blinkhs()', 1000);
+ blinking = 1;
+ }
+ }
+ }
+})
+
$("body").on('DOMSubtreeModified', "#hid_hs",
function () {
var hsnew = document.getElementById("hid_hs").innerHTML;
@@ -111,6 +163,7 @@ function () {
if (w) {
switch (hsnew) {
case "unsecured":
+ hscolor = csstate[0];
w.getElementsByClassName("hs_is")[0].setAttribute("fill", csstate[0]);
w.getElementsByClassName("hs_smb")[0].setAttribute("visibility", "hidden");
w.getElementsByClassName("hs_unlocked")[0].setAttribute("visibility", "visible");
@@ -118,6 +171,7 @@ function () {
w.getElementsByClassName("hs_eye")[0].setAttribute("visibility", "hidden");
break;
case "secured":
+ hscolor = csstate[1];
w.getElementsByClassName("hs_is")[0].setAttribute("fill", csstate[1]);
w.getElementsByClassName("hs_smb")[0].setAttribute("visibility", "hidden");
w.getElementsByClassName("hs_unlocked")[0].setAttribute("visibility", "hidden");
@@ -125,6 +179,7 @@ function () {
w.getElementsByClassName("hs_eye")[0].setAttribute("visibility", "hidden");
break;
case "protected":
+ hscolor = csstate[2];
w.getElementsByClassName("hs_is")[0].setAttribute("fill", csstate[2]);
w.getElementsByClassName("hs_smb")[0].setAttribute("visibility", "visible");
w.getElementsByClassName("hs_unlocked")[0].setAttribute("visibility", "hidden");
@@ -132,6 +187,7 @@ function () {
w.getElementsByClassName("hs_eye")[0].setAttribute("visibility", "hidden");
break;
case "guarded":
+ hscolor = csstate[3];
w.getElementsByClassName("hs_is")[0].setAttribute("fill", csstate[3]);
w.getElementsByClassName("hs_smb")[0].setAttribute("visibility", "visible");
w.getElementsByClassName("hs_unlocked")[0].setAttribute("visibility", "hidden");