From 2754323612d11e4042a8e1cf4cfd805755eedd20 Mon Sep 17 00:00:00 2001 From: risiko79 <> Date: Fri, 8 Jan 2016 23:19:28 +0000 Subject: [PATCH] 98_weekprofile: multi-select and send profile to other weekprofile modules git-svn-id: https://svn.fhem.de/fhem/trunk@10417 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 3 + fhem/FHEM/98_weekprofile.pm | 186 +++++++++++++++++++-------- fhem/www/pgm2/fhemweb_weekprofile.js | 111 ++++++++++++++-- 3 files changed, 231 insertions(+), 69 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index e933dc989..b0920f8f6 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,8 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 98_weekprofile: send profile to other weekprofile intance + send profile to multible devices + multi-select of devices in widget - feature: new module 52_I2C_PCA9685.pm added (klausw) - change: 98_weekprofile: create default profile if master device has no week profile diff --git a/fhem/FHEM/98_weekprofile.pm b/fhem/FHEM/98_weekprofile.pm index ad1b57f06..f813bab9d 100644 --- a/fhem/FHEM/98_weekprofile.pm +++ b/fhem/FHEM/98_weekprofile.pm @@ -20,6 +20,8 @@ use vars qw($init_done); my @shortDays = ("Mon","Tue","Wed","Thu","Fri","Sat","Sun"); +my @DEVLIST_SEND = ("MAX","CUL_HM","weekprofile","dummy"); + my %DEV_READINGS; # MAX $DEV_READINGS{"Mon"}{"MAX"} = "weekprofile-2-Mon"; @@ -58,9 +60,11 @@ $DEV_READINGS{"Sat"}{"HM-TC-IT-WM-W-EU"} = "R_P1_0_tempListSat"; $DEV_READINGS{"Sun"}{"HM-TC-IT-WM-W-EU"} = "R_P1_1_tempListSun"; ############################################## -sub weekprofile_getDeviceType($) +sub weekprofile_getDeviceType($;$) { - my ($device) = @_; + my ($device,$sndrcv) = @_; + + $sndrcv = "RCV" if (!defined($sndrcv)); # determine device type my $devHash = $main::defs{$device}; @@ -79,6 +83,13 @@ sub weekprofile_getDeviceType($) elsif ($devHash->{TYPE} =~ /dummy/){ $type = "MAX" if ($device =~ /.*MAX.*/); #dummy (FAKE WT) with name MAX inside for testing } + + return $type if ($sndrcv eq "RCV"); + + if ($devHash->{TYPE} =~ /weekprofile/){ + $type = "WEEKPROFILE"; + } + return $type; } @@ -168,15 +179,21 @@ sub weekprofile_createDefaultProfile(@) sub weekprofile_sendDevProfile(@) { my ($device,$prf,$me) = @_; - my $type = weekprofile_getDeviceType($device); + my $type = weekprofile_getDeviceType($device,"SND"); return "Error device type not supported" if (!defined ($type)); - + + if ($type eq "WEEKPROFILE") { + my $json = JSON->new; + my $json_text = $json->encode($prf->{DATA}); + return fhem("set $device profile_data $prf->{NAME} $json_text"); + } + my $devPrf = weekprofile_readDevProfile($device,$type,$me); # only send changed days my @dayToTransfer = (); foreach my $day (@shortDays){ - my $tmpCnt = scalar(@{$prf->{$day}->{"temp"}}); + my $tmpCnt = scalar(@{$prf->{DATA}->{$day}->{"temp"}}); next if ($tmpCnt <= 0); if ($tmpCnt != scalar(@{$devPrf->{$day}->{"temp"}})) { @@ -186,8 +203,8 @@ sub weekprofile_sendDevProfile(@) my $equal = 1; for (my $i = 0; $i < $tmpCnt; $i++) { - if ( ($prf->{$day}->{"temp"}[$i] ne $devPrf->{$day}->{"temp"}[$i] ) || - $prf->{$day}->{"time"}[$i] ne $devPrf->{$day}->{"time"}[$i] ) { + if ( ($prf->{DATA}->{$day}->{"temp"}[$i] ne $devPrf->{$day}->{"temp"}[$i] ) || + $prf->{DATA}->{$day}->{"time"}[$i] ne $devPrf->{$day}->{"time"}[$i] ) { $equal = 0; last; } @@ -208,15 +225,15 @@ sub weekprofile_sendDevProfile(@) if($type eq "MAX") { $cmd = "set $device weekProfile "; foreach my $day (@dayToTransfer){ - my $tmpCnt = scalar(@{$prf->{$day}->{"temp"}}); + my $tmpCnt = scalar(@{$prf->{DATA}->{$day}->{"temp"}}); $cmd.=$day.' '; for (my $i = 0; $i < $tmpCnt; $i++) { - my $endTime = $prf->{$day}->{"time"}[$i]; + my $endTime = $prf->{DATA}->{$day}->{"time"}[$i]; $endTime = ($endTime eq "24:00") ? ' ' : ','.$endTime.','; - $cmd.=$prf->{$day}->{"temp"}[$i].$endTime; + $cmd.=$prf->{DATA}->{$day}->{"temp"}[$i].$endTime; } } } else { #Homatic @@ -227,9 +244,9 @@ sub weekprofile_sendDevProfile(@) $cmd .= $day; $cmd .= ($k < $dayCnt-1) ? " prep": " exec"; - my $tmpCnt = scalar(@{$prf->{$day}->{"temp"}}); + my $tmpCnt = scalar(@{$prf->{DATA}->{$day}->{"temp"}}); for (my $i = 0; $i < $tmpCnt; $i++) { - $cmd .= " ".$prf->{$day}->{"time"}[$i]." ".$prf->{$day}->{"temp"}[$i]; + $cmd .= " ".$prf->{DATA}->{$day}->{"time"}[$i]." ".$prf->{DATA}->{$day}->{"temp"}[$i]; } $cmd .= ($k < $dayCnt-1) ? ";;": ""; $k++; @@ -240,6 +257,37 @@ sub weekprofile_sendDevProfile(@) fhem($cmd); return undef; } + +############################################## +sub weekprofile_refreshSendDevList($) +{ + my ($hash) = @_; + my $me = $hash->{NAME}; + + splice($hash->{SNDDEVLIST}); + + foreach my $d (keys %defs) + { + next if ($defs{$d}{NAME} eq $me); + + my $module = $defs{$d}{TYPE}; + + my %sndHash; + @sndHash{@DEVLIST_SEND}=(); + next if (!exists $sndHash{$module}); + + my $type = weekprofile_getDeviceType($defs{$d}{NAME},"SND"); + next if (!defined($type)); + + my $dev = {}; + $dev->{NAME} = $defs{$d}{NAME}; + $dev->{ALIAS} = AttrVal($dev->{NAME},"alias",$dev->{NAME}); + + push @{$hash->{SNDDEVLIST}} , $dev; + } + return undef; +} + ############################################## sub weekprofile_assignDev($) { @@ -345,11 +393,15 @@ sub weekprofile_Define($$) $hash->{STATE} = "defined"; my @profiles = (); + my @sendDevList = (); + $hash->{PROFILES} = \@profiles; + $hash->{SNDDEVLIST} = \@sendDevList; #$attr{$me}{verbose} = 5; if ($init_done) { + weekprofile_refreshSendDevList($hash); weekprofile_assignDev($hash); weekprofile_updateReadings($hash); } @@ -374,17 +426,9 @@ sub weekprofile_Get($$@) if($cmd eq "profile_data") { return "no profile" if ($prfCnt <= 0); - - my $prf = undef; - my $idx=0; - if($params[0]){ - foreach my $prf (@{$hash->{PROFILES}}){ - last if ( $prf->{NAME} eq $params[0]); - $idx++; - } - return "profile $params[0] not found" if ($idx >= $prfCnt); - } - $prf = $hash->{PROFILES}[$idx]; + + my ($prf,$idx) = weekprofile_findPRF($hash,$params[0]); + return "profile $params[0] not found" unless ($prf); my $json = JSON->new; my $json_text = $json->encode($prf->{DATA}); @@ -401,11 +445,34 @@ sub weekprofile_Get($$@) return $names; } + if($cmd eq "sndDevList") { + my $json = JSON->new; + my $json_text = $json->encode($hash->{SNDDEVLIST}); + return $json_text; + } $list =~ s/ $//; return "Unknown argument $cmd choose one of $list"; } ############################################## +sub weekprofile_findPRF(@) +{ + my ($hash, $profile) = @_; + + my $found = undef; + my $idx = 0; + foreach my $prf (@{$hash->{PROFILES}}){ + if ( $prf->{NAME} eq $profile){ + $found = $prf; + last; + } + $idx++; + } + $idx = -1 if (!defined($found)); + + return ($found,$idx); +} +############################################## sub weekprofile_Set($$@) { my ($hash, $me, $cmd, @params) = @_; @@ -430,7 +497,7 @@ sub weekprofile_Set($$@) $prf->{DATA} = $data; # automatic we send master profile to master device if ($params[0] eq "master"){ - weekprofile_sendDevProfile($hash->{MASTERDEV}->{NAME},$prf->{DATA},$me); + weekprofile_sendDevProfile($hash->{MASTERDEV}->{NAME},$prf,$me); } else { weekprofile_writeProfilesToFile($hash); } @@ -450,33 +517,34 @@ sub weekprofile_Set($$@) $list.= ' send_to_device' if ($prfCnt > 0); if ($cmd eq 'send_to_device') { - return 'usage: send_to_device [device]' if(@params < 1); + return 'usage: send_to_device [device(s)]' if(@params < 1); my $profile = $params[0]; - my $device = $hash->{MASTERDEV}->{NAME}; - if (@params == 2){ - $device = $params[1]; + my @devices = (); + if (@params == 2) { + @devices = split(',',$params[1]); + } else { + push @devices, $hash->{MASTERDEV}->{NAME} if (defined($hash->{MASTERDEV})); } - return "Error no master device" unless (defined($device)); + return "Error no devices given and no master device" if (@devices == 0); - my $found = undef; - foreach my $prf (@{$hash->{PROFILES}}){ - if ( $prf->{NAME} eq $profile){ - $found = $prf; - last; - } - } - - if (!$found) { + my ($found,$idx) = weekprofile_findPRF($hash,$profile); + if (!defined($found)) { Log3 $me, 1, "$me(Set): Error unknown profile $profile"; return "Error unknown profile $profile"; } - my $ret = weekprofile_sendDevProfile($device,$found->{DATA},$me); - Log3 $me, 1, "$me(Set): $ret" if ($ret); - return $ret; + my $err = ''; + foreach my $device (@devices){ + my $ret = weekprofile_sendDevProfile($device,$found,$me); + if ($ret) { + Log3 $me, 1, "$me(Set): $ret" if ($ret); + $err .= $ret . "\n"; + } + } + return $err; } #---------------------------------------------------------- $list.= " copy_profile"; @@ -514,15 +582,7 @@ sub weekprofile_Set($$@) return 'Error master profile can not removed' if($params[0] eq "master"); return 'Error Remove last profile is not allowed' if(scalar(@{$hash->{PROFILES}}) == 1); - my $delprf = undef; - my $idx = 0; - foreach my $prf (@{$hash->{PROFILES}}){ - if ( $prf->{NAME} eq $params[0]){ - $delprf = $prf; - last; - } - $idx++; - } + my ($delprf,$idx) = weekprofile_findPRF($hash,$params[0]); return "Error unknown profile $params[0]" unless($delprf); splice(@{$hash->{PROFILES}},$idx, 1); @@ -559,10 +619,15 @@ sub weekprofile_Notify($$) if ($what =~ m/INITIALIZED/) { splice($own->{PROFILES}); + weekprofile_refreshSendDevList($own); weekprofile_assignDev($own); weekprofile_readProfilesFromFile($own); weekprofile_updateReadings($own); } + + if ($what =~ m/DEFINED/ || $what =~ m/DELETED/) { + weekprofile_refreshSendDevList($own); + } } } @@ -714,7 +779,11 @@ sub weekprofile_SummaryFn() my $lnkDetails = AttrVal($d, "alias", $d); $lnkDetails = "$lnkDetails" if($show_links); - my $args = "weekprofile"; + my $masterDev = defined($hash->{MASTERDEV}) ? $hash->{MASTERDEV}->{NAME} : undef; + + my $args = "weekprofile,MODE:SHOW"; + $args .= ",MASTERDEV:$masterDev" if (defined($masterDev)); + my $curr = undef; $curr = $hash->{PROFILES}[0]->{NAME} if (@{$hash->{PROFILES}} > 0 ); @@ -738,7 +807,7 @@ sub weekprofile_editOnNewpage(@) my $hash = $defs{$device}; $backurl="?" if(!defined($backurl)); - my $args = "weekprofile,EDIT,$backurl"; + my $args = "weekprofile,MODE:EDIT,BACKURL:$backurl"; my $html; $html .= ""; @@ -811,6 +880,7 @@ sub weekprofile_getEditLNK_MasterDev($$) Mit dem Modul 'weekprofile' können mehrere Wochenprofile verwaltet und an unterschiedliche Geräte übertragen werden. Aktuell wird folgende Hardware unterstützt:
  • alle MAX Thermostate
  • +
  • andere weekprofile module
  • Homatic HM-CC-RT-DN
  • Homatic HM-CC-TC
  • Homatic HM-TC-IT-WM-W-EU
  • @@ -846,8 +916,9 @@ sub weekprofile_getEditLNK_MasterDev($$) Es wird das Profil 'profilname' geändert. Die Profildaten müssen im json-Format übergeben werden.
  • send_to_device
    - set <name> send_to_device <profilname> [device]
    - Das Profil wird an ein Gerät übertragen. Wird kein Gerät angegeben, wird das 'Master-Gerät' verwendet. + set <name> send_to_device <profilname> [devices]
    + Das Profil wird an ein oder mehrere Geräte übertragen. Wird kein Gerät angegeben, wird das 'Master-Gerät' verwendet. + 'Devices' ist eine kommagetrennte Auflistung von Geräten
  • copy_profile
    set <name> copy_profile <quelle> <ziel>
    @@ -904,6 +975,7 @@ sub weekprofile_getEditLNK_MasterDev($$) With this module you can manage and edit different weekprofiles. You can send the profiles to different devices.
    Currently the following devices will by supported:
  • MAX
  • +
  • other weekprofile modules
  • Homatic HM-CC-RT-DN
  • Homatic HM-CC-TC
  • Homatic HM-TC-IT-WM-W-EU
  • @@ -941,9 +1013,9 @@ sub weekprofile_getEditLNK_MasterDev($$) The profile 'profilename' will be changed. The data have to be in json format.
  • send_to_device
    - set <name> send_to_device <profilename> [device]
    - The profile 'profilename' will be transfered to the device. Without the parameter device the profile - will be transferd to the master device. + set <name> send_to_device <profilename> [devices]
    + The profile 'profilename' will be transfered to one or more the devices. Without the parameter device the profile + will be transferd to the master device. 'devices' is a comma seperated list of device names
  • copy_profile
    set <name> copy_profile <source> <destination>
    diff --git a/fhem/www/pgm2/fhemweb_weekprofile.js b/fhem/www/pgm2/fhemweb_weekprofile.js index 4dbcfdb16..a00d01e03 100644 --- a/fhem/www/pgm2/fhemweb_weekprofile.js +++ b/fhem/www/pgm2/fhemweb_weekprofile.js @@ -7,7 +7,7 @@ $(document).ready(function(){ var shortDays = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]; -function FW_weekprofileInputDialog(title,inp,parent, callback) +function FW_weekprofileInputDialog(title,inp,parent,callback) { var div = $("
    "); var content = $('').get(0); @@ -39,6 +39,65 @@ function FW_weekprofileInputDialog(title,inp,parent, callback) }); } +function FW_weekprofileMultiSelDialog(title, elementNames, elementLabels, selected,parent,callback) +{ + var table = ""; + if (elementNames) { + for(var i1=0; i1=0) + sel=1; + + table += ''; + table += ''; + } + } + table += "
    "; + + var div = $("
    "); + $(div).append(title); + $(div).append(table); + $(div).append(''); + $("body").append(div); + + $(div).dialog({ + dialogClass:"no-close",modal:true, width:"auto", closeOnEscape:true, + maxWidth:$(window).width()*0.9, maxHeight:$(window).height()*0.9, + title: title, + buttons: [{text:"OK", click:function(){ + var res=[]; + if($("#FW_weekprofileMultiSelDiologFreeText").val()) + res.push($("#FW_weekprofileMultiSelDiologFreeText").val()); + + $("#FW_weekprofileMultiSelDiolog table input").each(function(){ + if($(this).prop("checked")) + res.push($(this).attr("name")); + }); + $(this).dialog("close"); + $(div).remove(); + if(callback) + callback(res); + }},{text:"CANCEL", click:function(){ + $(this).dialog("close"); + $(div).remove(); + if(callback) + callback(null); + }}] + }); + + if(parent) + $(div).dialog( "option", "position", { + my: "left top", at: "right bottom", + of: parent, collision: "flipfit" + }); +} + function weekprofile_DoEditWeek(devName,newPage) { var widget = $('div[informid="'+devName+'"]').get(0); @@ -68,16 +127,39 @@ function FW_weekprofilePRFChached(devName,select) FW_queryValue('get '+devName+' profile_data '+prfName, widget); } -function FW_weekprofileSendToDev(devName,lnk) +function FW_weekprofileSendToDev(devName,bnt) { var widget = $('div[informid="'+devName+'"]').get(0) - FW_weekprofileInputDialog("Device:","text",lnk,function(device,ok){ - if (!device || device.length <=0) - return; - FW_cmd(FW_root+"?cmd=set "+widget.DEVICE+" send_to_device "+widget.CURPRF+" "+device+"&XHR=1",function(arg) {FW_weekprofileSendCallback(widget.DEVICE,arg);}); - }); -} + var deviceLst = null; + bnt.setValueFn = function(data) { + try { + deviceLst=JSON.parse(data); + var devicesNames = []; + var devicesAlias = []; + for (var k=0; k < deviceLst.length; k++) { + devicesNames.push(deviceLst[k]['NAME']); + devicesAlias.push(deviceLst[k]['ALIAS']); + } + var selected = []; + if (widget.MASTERDEV) + selected.push(widget.MASTERDEV); + FW_weekprofileMultiSelDialog("Device(s):",devicesNames,devicesAlias,selected,bnt, + function(sndDevs) { + if (!sndDevs || sndDevs.length==0) + return; + FW_cmd(FW_root+"?cmd=set "+widget.DEVICE+" send_to_device "+widget.CURPRF+" "+sndDevs.join(',')+"&XHR=1",function(arg) {FW_weekprofileSendCallback(widget.DEVICE,arg);}); + }); + + } catch(e){ + console.log(devName+" error parsing json '" +data+"'"); + FW_errmsg(devName+" Parameter "+e,5000); + return; + } + } + + FW_queryValue('get '+devName+' sndDevList', bnt); + } function FW_weekprofileCopyPrf(devName,lnk) { @@ -472,11 +554,16 @@ FW_weekprofileCreate(elName, devName, vArr, currVal, set, params, cmd) widget.SHOWURL = null; widget.MODE = 'SHOW'; - if (vArr.length > 1) { - widget.MODE = vArr[1]; - if (vArr.length > 2) - widget.SHOWURL = vArr[2]; + + for (var i = 1; i < vArr.length; ++i) { + var arg = vArr[i].split(':'); + switch (arg[0]) { + case "MODE": widget.MODE = arg[1]; break; + case "BACKURL": widget.SHOWURL = arg[1]; break; + case "MASTERDEV": widget.MASTERDEV = arg[1]; break; + } } + widget.DEVICE = devName; widget.WEEKDAYS = shortDays.slice(); widget.CURPRF = currVal;