| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490 |
- ##############################################
- # $Id: 98_weekprofile.pm 14084 2017-04-23 11:57:48Z Risiko $
- #
- # Usage
- #
- # define <name> weekprofile [device]
- ##############################################
- package main;
- use strict;
- use warnings;
- use JSON; #libjson-perl
- use vars qw(%defs);
- use vars qw($FW_ME);
- use vars qw($FW_wname);
- use vars qw($FW_subdir);
- use vars qw($init_done);
- my @shortDays = ("Mon","Tue","Wed","Thu","Fri","Sat","Sun");
- my @DEVLIST_SEND = ("MAX","CUL_HM","weekprofile","dummy");
- my $CONFIG_VERSION = "1.1";
- my %DEV_READINGS;
- # MAX
- $DEV_READINGS{"Mon"}{"MAX"} = "weekprofile-2-Mon";
- $DEV_READINGS{"Tue"}{"MAX"} = "weekprofile-3-Tue";
- $DEV_READINGS{"Wed"}{"MAX"} = "weekprofile-4-Wed";
- $DEV_READINGS{"Thu"}{"MAX"} = "weekprofile-5-Thu";
- $DEV_READINGS{"Fri"}{"MAX"} = "weekprofile-6-Fri";
- $DEV_READINGS{"Sat"}{"MAX"} = "weekprofile-0-Sat";
- $DEV_READINGS{"Sun"}{"MAX"} = "weekprofile-1-Sun";
- # CUL_HM
- $DEV_READINGS{"Mon"}{"CUL_HM"} = "2_tempListMon";
- $DEV_READINGS{"Tue"}{"CUL_HM"} = "3_tempListTue";
- $DEV_READINGS{"Wed"}{"CUL_HM"} = "4_tempListWed";
- $DEV_READINGS{"Thu"}{"CUL_HM"} = "5_tempListThu";
- $DEV_READINGS{"Fri"}{"CUL_HM"} = "6_tempListFri";
- $DEV_READINGS{"Sat"}{"CUL_HM"} = "0_tempListSat";
- $DEV_READINGS{"Sun"}{"CUL_HM"} = "1_tempListSun";
- sub weekprofile_findPRF($$$$);
- ##############################################
- sub weekprofile_getDeviceType($$;$)
- {
- my ($me,$device,$sndrcv) = @_;
-
- $sndrcv = "RCV" if (!defined($sndrcv));
- # determine device type
- my $devHash = $main::defs{$device};
- if (!defined($devHash)){
- return undef;
- }
-
- my $type = undef;
-
- if ($devHash->{TYPE} =~ /CUL_HM/){
- my $model = AttrVal($device,"model","");
-
- #models: HM-TC-IT-WM-W-EU, HM-CC-RT-DN, HM-CC-TC
- unless ($model =~ m/.*HM-[C|T]C-.*/) {
- Log3 $me, 4, "$me(getDeviceType): $devHash->{NAME}, model $model is not supported";
- return undef;
- }
-
- if (!defined($devHash->{chanNo})) { #no channel device
- Log3 $me, 4, "$me(getDeviceType): $devHash->{NAME}, model $model has no chanNo";
- return undef;
- }
-
- my $channel = $devHash->{chanNo};
- unless ($channel =~ /^\d+?$/) {
- Log3 $me, 4, "$me(getDeviceType): $devHash->{NAME}, model $model chanNo $channel is no number";
- return undef;
- }
-
- $channel += 0;
- Log3 $me, 5, "$me(getDeviceType): $devHash->{NAME}, $model, $channel";
-
- $type = "CUL_HM" if ( ($model =~ m/.*HM-CC-RT.*/) && ($channel == 4) );
- $type = "CUL_HM" if ( ($model =~ m/.*HM-TC.*/) && ($channel == 2) );
- $type = "CUL_HM" if ( ($model =~ m/.*HM-CC-TC.*/) && ($channel == 2) );
- }
- #avoid max shutter contact
- elsif ( ($devHash->{TYPE} =~ /MAX/) && ($devHash->{type} =~ /.*Thermostat.*/) ){
- $type = "MAX";
- }
- elsif ($devHash->{TYPE} =~ /dummy/){
- $type = "MAX" if ($device =~ m/.*MAX.*FAKE.*/); #dummy (FAKE WT) with name MAX inside for testing
- $type = "CUL_HM" if ($device =~ m/.*CUL_HM.*FAKE.*/); #dummy (FAKE WT) with name CUL_HM inside for testing
- }
-
- return $type if ($sndrcv eq "RCV");
-
- if ($devHash->{TYPE} =~ /weekprofile/){
- $type = "WEEKPROFILE";
- }
-
- if (defined($type)) {
- Log3 $me, 4, "$me(getDeviceType): $devHash->{NAME} is type $type";
- } else {
- Log3 $me, 4, "$me(getDeviceType): $devHash->{NAME} is not supported";
- }
- return $type;
- }
- ##############################################
- sub weekprofile_readDayProfile($@)
- {
- my ($device,$day,$type,$me) = @_;
- my @times;
- my @temps;
-
- $type = weekprofile_getDeviceType($me,$device) if (!defined($type));
- return if (!defined($type));
- my $reading = $DEV_READINGS{$day}{$type};
-
- #Log3 $me, 5, "$me(ReadDayProfile): $reading";
-
- if($type eq "MAX") {
- @temps = split('/',ReadingsVal($device,"$reading-temp",""));
- @times = split('/',ReadingsVal($device,"$reading-time",""));
- # only use to from interval 'from-to'
- for(my $i = 0; $i < scalar(@times); $i+=1){
- my $interval = $times[$i];
- my @parts = split('-',$interval);
- $times[$i] = ($parts[1] ne "00:00") ? $parts[1] : "24:00";
- }
- } elsif ($type eq "CUL_HM") {
- # get temp list for the day
- my $prf = ReadingsVal($device,"R_$reading","");
- $prf = ReadingsVal($device,"R_P1_$reading","") if (!$prf); #HM-TC-IT-WM-W-EU
-
- # split into time temp time temp etc.
- # 06:00 17.0 22:00 21.0 24:00 17.0
- my @timeTemp = split(' ', $prf);
-
- for(my $i = 0; $i < scalar(@timeTemp); $i += 2) {
- push(@times, $timeTemp[$i]);
- push(@temps, $timeTemp[$i+1]);
- }
- }
-
- for(my $i = 0; $i < scalar(@temps); $i+=1){
- $temps[$i] =~s/[^\d.]//g; #only numbers
- my $tempON = AttrVal($me, "tempON", undef);
- my $tempOFF = AttrVal($me, "tempOFF", undef);
-
- $temps[$i] =~s/$tempOFF/off/g if (defined($tempOFF)); # temp off
- $temps[$i] =~s/$tempON/on/g if (defined($tempON)); # temp on
- }
-
- for(my $i = 0; $i < scalar(@times); $i+=1){
- $times[$i] =~ s/^\s+|\s+$//g; #trim whitespace both ends
- }
- return (\@times, \@temps);
- }
- ##############################################
- sub weekprofile_readDevProfile(@)
- {
- my ($device,$type,$me) = @_;
- $type = weekprofile_getDeviceType($me, $device) if (!defined($type));
- return "" if (!defined ($type));
-
- my $prf = {};
- my $logDaysWarning="";
- my $logDaysCnt=0;
- foreach my $day (@shortDays){
- my ($dayTimes, $dayTemps) = weekprofile_readDayProfile($device,$day,$type,$me);
- if (scalar(@{$dayTemps})==0) {
- push(@{$dayTimes}, "24:00");
- push(@{$dayTemps}, "18.0");
- $logDaysWarning .= "\n" if ($logDaysCnt>0);
- $logDaysWarning .= "WARNING master device $device has no day profile for $day - create default";
- $logDaysCnt++;
- }
- $prf->{$day}->{"temp"} = $dayTemps;
- $prf->{$day}->{"time"} = $dayTimes;
- }
-
- if ( ($logDaysCnt>0) && ($logDaysCnt<(@shortDays)) ) {
- Log3 $me, 3, $logDaysWarning;
- } else {
- if ($logDaysCnt == (@shortDays)) {
- Log3 $me, 3, "WARNING master device $device has no week profile - create default";
- }
- }
-
- return $prf;
- }
- ##############################################
- sub weekprofile_createDefaultProfile(@)
- {
- my ($hash) = @_;
- my $prf = {};
-
- foreach my $day (@shortDays){
- my @times; push(@times, "24:00");
- my @temps; push(@temps, "18.0");
-
- $prf->{$day}->{"temp"} = \@temps;
- $prf->{$day}->{"time"} = \@times;
- }
- return $prf;
- }
- ##############################################
- sub weekprofile_sendDevProfile(@)
- {
- my ($device,$prf,$me) = @_;
- my $type = weekprofile_getDeviceType($me, $device,"SND");
-
- return "Error device type not supported" if (!defined ($type));
- return "profile has no data" if (!defined($prf->{DATA}));
- if ($type eq "WEEKPROFILE") {
- my $json = JSON->new;
- my $json_text = $json->encode($prf->{DATA});
- return fhem("set $device profile_data $prf->{TOPIC}:$prf->{NAME} $json_text",1);
- }
- my $devPrf = weekprofile_readDevProfile($device,$type,$me);
-
- # only send changed days
- my @dayToTransfer = ();
- foreach my $day (@shortDays){
- my $tmpCnt = scalar(@{$prf->{DATA}->{$day}->{"temp"}});
- next if ($tmpCnt <= 0);
-
- if ($tmpCnt != scalar(@{$devPrf->{$day}->{"temp"}})) {
- push @dayToTransfer , $day;
- next;
- }
-
- my $equal = 1;
- for (my $i = 0; $i < $tmpCnt; $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;
- }
- }
-
- if ($equal == 0) {
- push @dayToTransfer , $day;
- next;
- }
- }
-
- if (scalar(@dayToTransfer) <=0) {
- Log3 $me, 4, "$me(sendDevProfile): nothing to do";
- return undef;
- }
-
- my $cmd;
- if($type eq "MAX") {
- $cmd = "set $device weekProfile ";
- foreach my $day (@dayToTransfer){
- my $tmpCnt = scalar(@{$prf->{DATA}->{$day}->{"temp"}});
-
- $cmd.=$day.' ';
-
- for (my $i = 0; $i < $tmpCnt; $i++) {
- my $endTime = $prf->{DATA}->{$day}->{"time"}[$i];
-
- $endTime = ($endTime eq "24:00") ? ' ' : ','.$endTime.',';
- $cmd.=$prf->{DATA}->{$day}->{"temp"}[$i].$endTime;
- }
- }
- } else { #Homatic
- my $k=0;
- my $dayCnt = scalar(@dayToTransfer);
- foreach my $day (@dayToTransfer){
- $cmd .= "set $device tempList";
- $cmd .= $day;
- $cmd .= ($k < $dayCnt-1) ? " prep": " exec";
-
- my $tmpCnt = scalar(@{$prf->{DATA}->{$day}->{"temp"}});
- for (my $i = 0; $i < $tmpCnt; $i++) {
- $cmd .= " ".$prf->{DATA}->{$day}->{"time"}[$i]." ".$prf->{DATA}->{$day}->{"temp"}[$i];
- }
- $cmd .= ($k < $dayCnt-1) ? "; ": "";
- $k++;
- }
- }
- my $ret = undef;
- if ($cmd) {
- $cmd =~ s/^\s+|\s+$//g;
- Log3 $me, 4, "$me(sendDevProfile): $cmd";
- $ret = fhem($cmd,1);
- DoTrigger($me,"PROFILE_TRANSFERED $device",1);
- }
- return $ret;
- }
- ##############################################
- sub weekprofile_refreshSendDevList($)
- {
- my ($hash) = @_;
- my $me = $hash->{NAME};
-
- delete $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($me, $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($)
- {
- my ($hash) = @_;
- my $me = $hash->{NAME};
-
- my $prf = undef;
- if (defined($hash->{MASTERDEV})) {
-
- Log3 $me, 5, "$me(assignDev): assign to device $hash->{MASTERDEV}->{NAME}";
-
- my $type = weekprofile_getDeviceType($me, $hash->{MASTERDEV}->{NAME});
- if (!defined($type)) {
- Log3 $me, 2, "$me(assignDev): device $hash->{MASTERDEV}->{NAME} not supported or defined";
- } else {
- $hash->{MASTERDEV}->{TYPE} = $type;
-
- my $prfDev = weekprofile_readDevProfile($hash->{MASTERDEV}->{NAME},$type, $me);
-
- $prf = {};
- $prf->{NAME} = 'master';
- $prf->{TOPIC} = 'default';
-
- if(defined($prfDev)) {
- $prf->{DATA} = $prfDev;
- } else {
- Log3 $me, 3, "WARNING master device $hash->{MASTERDEV}->{NAME} has no week profile - create default profile";
- $prf->{DATA} = weekprofile_createDefaultProfile($hash);
- }
- $hash->{STATE} = "assigned";
- }
- }
-
- if (!defined($prf)) {
- my $prfDev = weekprofile_createDefaultProfile($hash);
- if(defined($prfDev)) {
- $prf = {};
- $prf->{DATA} = $prfDev;
- $prf->{NAME} = 'default';
- $prf->{TOPIC} = 'default';
- }
- $hash->{STATE} = "created";
- }
-
- if(defined($prf)) {
- push @{$hash->{PROFILES}} , $prf;
- }
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash,"state",$hash->{STATE});
- readingsEndUpdate($hash, 1);
- }
- ##############################################
- sub weekprofile_updateReadings($)
- {
- my ($hash) = @_;
-
- my $prfCnt = scalar(@{$hash->{PROFILES}});
-
- readingsBeginUpdate($hash);
- readingsBulkUpdate($hash,"profile_count",$prfCnt);
-
- #readings with profile names???
- #my $idx = 1;
- #foreach my $prf (@{$hash->{PROFILES}}){
- #my $str = sprintf("profile_name_%02d",$idx);
- #readingsBulkUpdate($hash,$str,$prf->{NAME});
- #$idx++;
- #}
-
- splice(@{$hash->{TOPICS}});
- foreach my $prf (@{$hash->{PROFILES}}) {
- if ( !grep( /^$prf->{TOPIC}$/, @{$hash->{TOPICS}}) ) {
- push @{$hash->{TOPICS}}, $prf->{TOPIC};
- }
- }
- readingsEndUpdate($hash, 1);
- }
- ##############################################
- sub weekprofile_Initialize($)
- {
- my ($hash) = @_;
- $hash->{DefFn} = "weekprofile_Define";
- $hash->{SetFn} = "weekprofile_Set";
- $hash->{GetFn} = "weekprofile_Get";
- $hash->{SetFn} = "weekprofile_Set";
- $hash->{StateFn} = "weekprofile_State";
- $hash->{NotifyFn} = "weekprofile_Notify";
- $hash->{AttrFn} = "weekprofile_Attr";
- $hash->{AttrList} = "useTopics:0,1 widgetTranslations widgetWeekdays widgetEditOnNewPage:0,1 widgetEditDaysInRow:1,2,3,4,5,6,7 tempON tempOFF configFile ".$readingFnAttributes;
-
- $hash->{FW_summaryFn} = "weekprofile_SummaryFn";
- $hash->{FW_atPageEnd} = 1;
- }
- ##############################################
- sub weekprofile_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- if(@a < 1) {
- my $msg = "wrong syntax: define <name> weekprofile [device]";
- Log3 undef, 2, $msg;
- return $msg;
- }
- my $me = $a[0];
-
- my $devName = undef;
- if (@a > 1) {
- $devName = $a[2];
- $devName =~ s/(^\s+|\s+$)//g if ($devName);
- }
- $hash->{MASTERDEV}->{NAME} = $devName if (defined($devName));
-
- $hash->{STATE} = "defined";
- my @profiles = ();
- my @sendDevList = ();
- my @topics = ();
-
- $hash->{PROFILES} = \@profiles;
- $hash->{SNDDEVLIST} = \@sendDevList;
- $hash->{TOPICS} = \@topics;
-
- #$attr{$me}{verbose} = 5;
-
- if ($init_done) {
- weekprofile_refreshSendDevList($hash);
- weekprofile_assignDev($hash);
- weekprofile_updateReadings($hash);
- }
- return undef;
- }
- ##############################################
- sub sort_by_name
- {
- return lc("$a->{TOPIC}:$a->{NAME}") cmp lc("$b->{TOPIC}:$b->{NAME}");
- }
- ##############################################
- sub weekprofile_Get($$@)
- {
- my ($hash, $name, $cmd, @params) = @_;
-
- my $list = '';
-
- my $prfCnt = scalar(@{$hash->{PROFILES}});
-
- my $useTopics = AttrVal($name,"useTopics",0);
-
- $list.= 'profile_data:' if ($prfCnt > 0);
- foreach my $prf (sort sort_by_name @{$hash->{PROFILES}}){
- $list.= $prf->{TOPIC}.":" if ($useTopics);
- $list.= $prf->{NAME}."," if ($useTopics || (!$useTopics && ($prf->{TOPIC} eq 'default')));
- }
- $list = substr($list, 0, -1) if ($prfCnt > 0);
-
- #-----------------------------------------------------------------------------
- if($cmd eq "profile_data") {
- return 'usage: profile_data <name>' if(@params < 1);
- return "no profile" if ($prfCnt <= 0);
-
- my ($topic, $name) = weekprofile_splitName($params[0]);
- my ($prf,$idx) = weekprofile_findPRF($hash,$name,$topic,1);
-
- return "profile $params[0] not found" if (!defined($prf));
- return "profile $params[0] has no data" if (!defined($prf->{DATA}));
-
- my $json = JSON->new;
- my $json_text = $json->encode($prf->{DATA});
- return $json_text;
- }
- #-----------------------------------------------------------------------------
- $list.= ' profile_names';
- if($cmd eq "profile_names") {
- my $names = '';
- my $topic = 'default';
- $topic = $params[0] if(@params == 1);
-
- foreach my $prf (sort sort_by_name @{$hash->{PROFILES}}){
- $names .=$prf->{NAME}."," if ($topic eq $prf->{TOPIC});
- $names .="$prf->{TOPIC}:$prf->{NAME}," if ($topic eq '*');
- }
- if ($names) {
- $names = substr($names, 0, -1);
- $names =~ s/ $//;
- }
- return $names;
- }
- #-----------------------------------------------------------------------------
- $list.= ' profile_references' if ($useTopics);
- if($cmd eq "profile_references") {
- return 'usage: profile_references <name>' if(@params < 1);
- my $refs = '';
- my $topic = 'default';
-
- if ($params[0] eq '*') {
- foreach my $prf (sort sort_by_name @{$hash->{PROFILES}}){
- next if (!defined($prf->{REF}));
- $refs .= "$prf->{TOPIC}:$prf->{NAME}>$prf->{REF},";
- }
- $refs = substr($refs, 0, -1);
- } else {
- my ($topic, $name) = weekprofile_splitName($params[0]);
- my ($prf,$idx) = weekprofile_findPRF($hash,$name,$topic,0);
- return "profile $params[0] not found" unless ($prf);
- $refs = '0';
- $refs = "$prf->{REF}" if ($prf->{REF});
- }
- return $refs;
- }
-
- #-----------------------------------------------------------------------------
- $list.= ' topic_names:noArg' if ($useTopics);
- if($cmd eq "topic_names") {
- my $names = '';
- foreach my $topic (sort {lc($a) cmp lc($b)} @{$hash->{TOPICS}}) {
- $names .= "$topic,";
- }
- if ($names) {
- $names = substr($names, 0, -1);
- $names =~ s/ $//;
- }
- return $names;
- }
-
- if($cmd eq "sndDevList") {
- my $json = JSON->new;
- my @sortDevList = sort {lc($a->{ALIAS}) cmp lc($b->{ALIAS})} @{$hash->{SNDDEVLIST}};
- my $json_text = $json->encode(\@sortDevList);
- return $json_text;
- }
-
- $list =~ s/ $//;
- return "Unknown argument $cmd choose one of $list";
- }
- ##############################################
- sub weekprofile_findPRF($$$$)
- {
- my ($hash, $name, $topic, $followRef) = @_;
-
- $topic = 'default' if (!$topic);
- $followRef = '0' if (!$followRef);
-
- my $found = undef;
- my $idx = 0;
-
- foreach my $prf (@{$hash->{PROFILES}}){
- if ( ($prf->{NAME} eq $name) && ($prf->{TOPIC} eq $topic) ){
- $found = $prf;
- last;
- }
- $idx++;
- }
- $idx = -1 if (!defined($found));
-
- if ($followRef == 1 && defined($found) && defined($found->{REF})) {
- ($topic, $name) = weekprofile_splitName($found->{REF});
- ($found,$idx) = weekprofile_findPRF($hash,$name,$topic,0);
- }
-
- return ($found,$idx);
- }
- ##############################################
- sub weekprofile_hasREF(@)
- {
- my ($hash, $refPrf) = @_;
-
- my $refName = "$refPrf->{TOPIC}:$refPrf->{NAME}";
-
- foreach my $prf (@{$hash->{PROFILES}}){
- if ( defined($prf->{REF}) && ($prf->{REF} eq $refName) ) {
- return "$prf->{TOPIC}:$prf->{NAME}";
- }
- }
- return undef;
- }
- ##############################################
- sub weekprofile_splitName($)
- {
- my ($in) = @_;
-
- my @parts = split(':',$in);
-
- return ($parts[0],$parts[1]) if (@parts == 2);
- return ('default',$in);
- }
- ##############################################
- sub weekprofile_Set($$@)
- {
- my ($hash, $me, $cmd, @params) = @_;
- my $prfCnt = scalar(@{$hash->{PROFILES}});
- my $list = '';
- my $useTopics = AttrVal($me,"useTopics",0);
-
- $list.= "profile_data";
- if ($cmd eq 'profile_data') {
- return 'usage: profile_data <name> <json data>' if(@params < 2);
-
- my ($topic, $name) = weekprofile_splitName($params[0]);
-
- return "Error topics not enabled" if (!$useTopics && ($topic ne 'default'));
-
- my $jsonData = $params[1];
- my $json = JSON->new;
- my $data = undef;
- eval { $data = $json->decode($jsonData); };
- if ($@) {
- Log3 $me, 1, "$me(Set): Error parsing profile data.";
- return "Error parsing profile data. No valid json format";
- };
-
- my ($found,$idx) = weekprofile_findPRF($hash,$name,$topic,1);
- if (defined($found)) {
- $found->{DATA} = $data;
- # automatic we send master profile to master device
- if ( ($name eq "master") && defined($hash->{MASTERDEV}) ){
- weekprofile_sendDevProfile($hash->{MASTERDEV}->{NAME},$found,$me);
- } else {
- weekprofile_writeProfilesToFile($hash);
- }
- return undef;
- }
- my $prfNew = {};
- $prfNew->{NAME} = $name;
- $prfNew->{DATA} = $data;
- $prfNew->{TOPIC} = $topic;
-
- push @{$hash->{PROFILES}}, $prfNew;
- weekprofile_writeProfilesToFile($hash);
- return undef;
- }
- #----------------------------------------------------------
- $list.= ' send_to_device' if ($prfCnt > 0);
-
- if ($cmd eq 'send_to_device') {
- return 'usage: send_to_device <name> [device(s)]' if(@params < 1);
-
- my ($topic, $name) = weekprofile_splitName($params[0]);
-
- return "Error topics not enabled" if (!$useTopics && ($topic ne 'default'));
-
- my @devices = ();
- if (@params == 2) {
- @devices = split(',',$params[1]);
- } else {
- push @devices, $hash->{MASTERDEV}->{NAME} if (defined($hash->{MASTERDEV}));
- }
-
- return "Error no devices given and no master device" if (@devices == 0);
-
- my ($found,$idx) = weekprofile_findPRF($hash,$name,$topic,1);
- if (!defined($found)) {
- Log3 $me, 1, "$me(Set): Error unknown profile $params[0]";
- return "Error unknown profile $params[0]";
- }
-
- 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";
- if ($cmd eq 'copy_profile') {
- return 'usage: copy_profile <source> <target>' if(@params < 2);
-
- my ($srcTopic, $srcName) = weekprofile_splitName($params[0]);
- my ($destTopic, $destName) = weekprofile_splitName($params[1]);
-
- return "Error topics not enabled" if (!$useTopics && ( ($srcTopic ne 'default') || ($destTopic ne 'default')) );
-
- my $prfSrc = undef;
- my $prfDest = undef;
- foreach my $prf (@{$hash->{PROFILES}}){
- $prfSrc = $prf if ( ($prf->{NAME} eq $srcName) && ($prf->{TOPIC} eq $srcTopic) );
- $prfDest = $prf if ( ($prf->{NAME} eq $destName) && ($prf->{TOPIC} eq $destTopic) );
- }
- return "Error unknown profile $srcName" unless($prfSrc);
- Log3 $me, 4, "$me(Set): override profile $destName" if ($prfDest);
-
- if ($prfDest){
- $prfDest->{DATA} = $prfSrc->{DATA};
- $prfDest->{REF} = $prfSrc->{REF};
- } else {
- $prfDest = {};
- $prfDest->{NAME} = $destName;
- $prfDest->{DATA} = $prfSrc->{DATA};
- $prfDest->{TOPIC} = $destTopic;
- $prfDest->{REF} = $prfSrc->{REF};
- push @{$hash->{PROFILES}}, $prfDest;
- }
- weekprofile_writeProfilesToFile($hash);
- return undef;
- }
-
- #----------------------------------------------------------
- $list.= " reference_profile" if ($useTopics);
- if ($cmd eq 'reference_profile') {
- return 'usage: copy_profile <source> <target>' if(@params < 2);
-
- my ($srcTopic, $srcName) = weekprofile_splitName($params[0]);
- my ($destTopic, $destName) = weekprofile_splitName($params[1]);
-
- return "Error topics not enabled" if (!$useTopics && ( ($srcTopic ne 'default') || ($destTopic ne 'default')) );
-
- my $prfSrc = undef;
- my $prfDest = undef;
- foreach my $prf (@{$hash->{PROFILES}}){
- $prfSrc = $prf if ( ($prf->{NAME} eq $srcName) && ($prf->{TOPIC} eq $srcTopic) );
- $prfDest = $prf if ( ($prf->{NAME} eq $destName) && ($prf->{TOPIC} eq $destTopic) );
- }
- return "Error unknown profile $srcName" unless($prfSrc);
- Log3 $me, 4, "$me(Set): override profile $destName" if ($prfDest);
-
- if ($prfDest){
- $prfDest->{DATA} = undef;
- $prfDest->{REF} = "$srcTopic:$srcName";
- } else {
- $prfDest = {};
- $prfDest->{NAME} = $destName;
- $prfDest->{DATA} = undef;
- $prfDest->{TOPIC} = $destTopic;
- $prfDest->{REF} = "$srcTopic:$srcName";
- push @{$hash->{PROFILES}}, $prfDest;
- }
- weekprofile_writeProfilesToFile($hash);
- return undef;
- }
-
- #----------------------------------------------------------
- $list.= " remove_profile";
- if ($cmd eq 'remove_profile') {
- return 'usage: remove_profile <name>' if(@params < 1);
- return 'Error master profile can not removed' if( ($params[0] eq "master") && defined($hash->{MASTERDEV}) );
- return 'Error Remove last profile is not allowed' if(scalar(@{$hash->{PROFILES}}) == 1);
-
- my ($topic, $name) = weekprofile_splitName($params[0]);
-
- return "Error topics not enabled" if (!$useTopics && ($topic ne 'default'));
-
- my ($delprf,$idx) = weekprofile_findPRF($hash,$name,$topic,0);
- return "Error unknown profile $params[0]" unless($delprf);
- my $ref = weekprofile_hasREF($hash,$delprf);
- return "Error profile $params[0] is referenced from $ref" if ($ref);
-
- splice(@{$hash->{PROFILES}},$idx, 1);
- weekprofile_writeProfilesToFile($hash);
- return undef;
- }
-
-
- #----------------------------------------------------------
- $list.= " restore_topic" if ($useTopics);
- if ($cmd eq 'restore_topic') {
- return 'usage: restore_topic <name>' if(@params < 1);
-
- my $topic = $params[0];
- my $err='';
-
- foreach my $dev (@{$hash->{SNDDEVLIST}}){
- my $prfName = AttrVal($dev->{NAME},"weekprofile",undef);
- next if (!defined($prfName));
-
- Log3 $me, 5, "$me(Set): found device $dev->{NAME}";
-
- my ($prf,$idx) = weekprofile_findPRF($hash,$prfName,$topic,1);
- next if (!defined($prf));
-
- Log3 $me, 4, "$me(Set): Send profile $topic:$prfName to $dev->{NAME}";
-
- my $ret = weekprofile_sendDevProfile($dev->{NAME},$prf,$me);
- if ($ret) {
- Log3 $me, 1, "$me(Set): $ret" if ($ret);
- $err .= $ret . "\n";
- }
- }
- readingsSingleUpdate($hash,"active_topic",$topic,1);
- return $err if ($err);
- return undef;
- }
-
- $list =~ s/ $//;
- return "Unknown argument $cmd, choose one of $list";
- }
- ##############################################
- sub weekprofile_State($$$$)
- {
- my ($hash, $time, $name, $val) = @_;
- my $me = $hash->{NAME};
- #do nothing we do not restore readings from statefile
- return undef;
- }
- ##############################################
- sub weekprofile_Notify($$)
- {
- my ($own, $dev) = @_;
- my $me = $own->{NAME}; # own name / hash
- my $devName = $dev->{NAME}; # Device that created the events
- my $max = int(@{$dev->{CHANGED}}); # number of events / changes
-
- if ($devName eq "global"){
- for (my $i = 0; $i < $max; $i++) {
- my $s = $dev->{CHANGED}[$i];
-
- next if(!defined($s));
- my ($what,$who) = split(' ',$s);
-
- if ($what =~ m/^INITIALIZED$/ || $what =~ m/REREADCFG/) {
- delete $own->{PROFILES};
- weekprofile_refreshSendDevList($own);
- weekprofile_assignDev($own);
- weekprofile_readProfilesFromFile($own);
- weekprofile_updateReadings($own);
- }
-
- if ($what =~ m/DEFINED/ || $what =~ m/^DELETED/) {
- weekprofile_refreshSendDevList($own);
- }
- }
- }
-
- if ($init_done && defined($own->{MASTERDEV}) &&
- ($own->{MASTERDEV}->{NAME} eq $devName) &&
- (@{$own->{PROFILES}} > 0) ) {
-
- my $readprf=0;
-
- for (my $i = 0; $i < $max; $i++) {
- my $s = $dev->{CHANGED}[$i];
-
- next if(!defined($s));
- my ($what,$who) = split(' ',$s);
-
- Log3 $me, 5, "$me(Notify): $devName, $what";
-
- if ($own->{MASTERDEV}->{NAME} eq 'MAX') {
- $readprf =1 if ($what=~m/weekprofile/); #reading weekprofile
- } else {
- # toDo nur auf spezielle notify bei anderen typen reagieren!!
- $readprf = 1;
- }
-
- last if ($readprf);
- }
-
- if ($readprf) {
- Log3 $me, 4, "$me(Notify): reread master profile from $devName";
- my $prfDev = weekprofile_readDevProfile($own->{MASTERDEV}->{NAME},$own->{MASTERDEV}->{TYPE}, $me);
- if(defined($prfDev)) {
- $own->{PROFILES}[0]->{DATA} = $prfDev;
- weekprofile_updateReadings($own);
- }
- }
- }
- return undef;
- }
- ##############################################
- sub weekprofile_Attr($$$)
- {
- my ($cmd, $me, $attrName, $attrVal) = @_;
-
- my $hash = $defs{$me};
-
- Log3 $me, 5, "$me(weekprofile_Attr): $cmd, $attrName, $attrVal";
-
- $attr{$me}{$attrName} = $attrVal;
- weekprofile_writeProfilesToFile($hash) if ($attrName eq 'configFile');
- return undef;
-
- }
- ##############################################
- sub weekprofile_writeProfilesToFile(@)
- {
- my ($hash) = @_;
- my $me = $hash->{NAME};
-
- my $start = (defined($hash->{MASTERDEV})) ? 1:0;
- my $prfCnt = scalar(@{$hash->{PROFILES}});
- return if ($prfCnt <= $start);
- my $filename = "./log/weekprofile-$me.cfg";
- $filename = AttrVal($me,"configFile",$filename);
- my $ret = open(my $fh, '>', $filename);
- if (!$ret){
- Log3 $me, 1, "$me(writeProfileToFile): Could not open file '$filename' $!";
- return;
- }
-
- print $fh "__version__=".$CONFIG_VERSION."\n";
-
- Log3 $me, 5, "$me(writeProfileToFile): write profiles to $filename";
- my $json = JSON->new;
- for (my $i = $start; $i < $prfCnt; $i++) {
- print $fh "entry=".$json->encode($hash->{PROFILES}[$i])."\n";
- }
- close $fh;
- DoTrigger($me,"PROFILES_SAVED",1);
- weekprofile_updateReadings($hash);
- }
- ##############################################
- sub weekprofile_readProfilesFromFile(@)
- {
- my ($hash) = @_;
- my $me = $hash->{NAME};
-
- my $useTopics = AttrVal($me,"useTopics",0);
- my $filename = "./log/weekprofile-$me.cfg";
- $filename = AttrVal($me,"configFile",$filename);
-
- unless (-e $filename) {
- Log3 $me, 5, "$me(readProfilesFromFile): file do not exist '$filename'";
- return;
- }
-
- #my $ret = open(my $fh, '<:encoding(UTF-8)', $filename);
- my $ret = open(my $fh, '<', $filename);
- if (!$ret){
- Log3 $me, 1, "$me(readProfilesFromFile): Could not open file '$filename' $!";
- return;
- }
-
- Log3 $me, 5, "$me(readProfilesFromFile): read profiles from $filename";
-
- my $json = JSON->new;
- my $rowCnt = 0;
- my $version = undef;
- while (my $row = <$fh>) {
- chomp $row;
- Log3 $me, 5, "$me(readProfilesFromFile): data row $row";
- my @data = split('=',$row);
- if(@data<2){
- Log3 $me, 1, "$me(readProfilesFromFile): incorrect data row";
- next;
- }
-
- if ($rowCnt == 0 && $data[0]=~/__version__/) {
- $version=$data[1] * 1;
- Log3 $me, 5, "$me(readProfilesFromFile): detect version $version";
- next;
- }
-
- if (!$version || $version < 1.1) {
- my $prfData=undef;
- eval { $prfData = $json->decode($data[1]); };
- if ($@) {
- Log3 $me, 1, "$me(readProfilesFromFile): Error parsing profile data $data[1]";
- next;
- };
-
- my $prfNew = {};
- $prfNew->{NAME} = $data[0];
- $prfNew->{DATA} = $prfData;
- $prfNew->{TOPIC} = 'default';
-
- if (!$hash->{MASTERDEV} && $rowCnt == 0) {
- $hash->{PROFILES}[0] = $prfNew; # replace default
- } else {
- push @{$hash->{PROFILES}}, $prfNew;
- }
- $rowCnt++;
- } #----------------------------------------------------- 1.1
- elsif ($version = 1.1) {
- my $prfNew=undef;
- eval { $prfNew = $json->decode($data[1]); };
- if ($@) {
- Log3 $me, 1, "$me(readProfilesFromFile): Error parsing profile data $data[1]";
- next;
- };
-
- next if (!$useTopics && ($prfNew->{TOPIC} ne 'default')); # remove topics!!
-
- if (!$hash->{MASTERDEV} && $rowCnt == 0) {
- $hash->{PROFILES}[0] = $prfNew; # replace default
- } else {
- push @{$hash->{PROFILES}}, $prfNew;
- }
- $rowCnt++;
- } else {
- Log3 $me, 1, "$me(readProfilesFromFile): Error unknown version $version";
- close $fh;
- return;
- }
- }
- close $fh;
- }
- ##############################################
- sub weekprofile_SummaryFn()
- {
- my ($FW_wname, $d, $room, $extPage) = @_;
- my $hash = $defs{$d};
-
- my $show_links = 1;
- $show_links = 0 if($FW_hiddenroom{detail});
- my $html;
-
- my $iconName = AttrVal($d, "icon", "edit_settings");
- my $editNewpage = AttrVal($d, "widgetEditOnNewPage", 0);
- my $useTopics = AttrVal($d, "useTopics", 0);
- my $editDaysInRow = AttrVal($d, "widgetEditDaysInRow", undef);
- my $tempON = AttrVal($d, "tempON", undef);
- my $tempOFF = AttrVal($d, "tempOFF", undef);
-
- my $editIcon = FW_iconName($iconName) ? FW_makeImage($iconName,$iconName,"icon") : "";
- $editIcon = "<a name=\"$d.edit\" onclick=\"weekprofile_DoEditWeek('$d','$editNewpage')\" href=\"javascript:void(0)\">$editIcon</a>";
-
- my $lnkDetails = AttrVal($d, "alias", $d);
- $lnkDetails = "<a name=\"$d.detail\" href=\"$FW_ME$FW_subdir?detail=$d\">$lnkDetails</a>" if($show_links);
-
- my $masterDev = defined($hash->{MASTERDEV}) ? $hash->{MASTERDEV}->{NAME} : undef;
-
- my $args = "weekprofile,MODE:SHOW";
- $args .= ",USETOPICS:$useTopics";
- $args .= ",MASTERDEV:$masterDev" if (defined($masterDev));
- $args .= ",DAYINROW:$editDaysInRow" if (defined($editDaysInRow));
- $args .= ",TEMP_ON:$tempON" if (defined($tempON));
- $args .= ",TEMP_OFF:$tempOFF" if (defined($tempOFF));
-
- my $curr = "";
- if (@{$hash->{PROFILES}} > 0)
- {
- $curr = "$hash->{PROFILES}[0]->{TOPIC}:$hash->{PROFILES}[0]->{NAME}";
- my $currTopic = ReadingsVal($d, "active_topic", undef);
- if ($currTopic) {
- foreach my $prf (@{$hash->{PROFILES}}){
- if ($prf->{TOPIC} eq $currTopic){
- $curr = "$prf->{TOPIC}:$prf->{NAME}";
- last;
- }
- }
- }
- }
-
- $html .= "<table>";
- $html .= "<tr><td>";
- $html .= "<div class=\"devType\" id=\"weekprofile.$d.header\">";
- $html .= "<table style=\"padding:0\"><tr><td style=\"padding-right:0;padding-bottom:0\"><div id=\"weekprofile.menu.base\">";
- $html .= $editIcon." ".$lnkDetails;
- $html .= "</div></td></tr></table></div></td></tr>";
- $html .= "<tr><td>";
- $html .= "<div class=\"fhemWidget\" informId=\"$d\" cmd=\"\" arg=\"$args\" current=\"$curr\" dev=\"$d\">"; # div tag to support inform updates
- $html .= "</div>";
- $html .= "</td></tr>";
- $html .= "</table>";
- return $html;
- }
- ##############################################
- sub weekprofile_editOnNewpage(@)
- {
- my ($device, $prf, $daysInRow) = @_;
- my $hash = $defs{$device};
-
- my $editDaysInRow = AttrVal($device, "widgetEditDaysInRow", undef);
- $editDaysInRow = $daysInRow if (defined($daysInRow));
-
- my $args = "weekprofile,MODE:EDIT,JMPBACK:1";
- $args .= ",DAYINROW:$editDaysInRow" if (defined($editDaysInRow));
-
- my $html;
- $html .= "<html>";
- $html .= "<table>";
- $html .= "<tr><td>";
- $html .= "<div class=\"devType\" id=\"weekprofile.$device.header\">";
- $html .= "<div class=\"devType\" id=\"weekprofile.menu.base\">";
- $html .= "</di></div></td></tr>";
- $html .= "<tr><td>";
- $html .= "<div class=\"fhemWidget\" informId=\"$device\" cmd=\"\" arg=\"$args\" current=\"$prf\" dev=\"$device\">"; # div tag to support inform updates
- $html .= "</div>";
- $html .= "</td></tr>";
- $html .= "</table>";
- $html .= "</html>";
- return $html;
- }
- ##############################################
- #search device weekprofile from a assoziated master device
- sub weekprofile_findPRFDev($)
- {
- my ($device) = @_;
-
- foreach my $d (keys %defs)
- {
- my $module = $defs{$d}{TYPE};
-
- next if ("$module" ne "weekprofile");
-
- next if (!defined($defs{$d}->{MASTERDEV}));
- my $masterDev = $defs{$d}->{MASTERDEV}->{NAME};
- next unless(defined($masterDev));
- next if ($masterDev ne $device);
-
- return $defs{$d}{NAME};
- }
- return undef;
- }
- ##############################################
- # get a web link to edit a profile from weekprofile from a assoziated master device
- sub weekprofile_getEditLNK_MasterDev($$)
- {
- my ($aszDev, $prf) = @_;
-
- my $device = weekprofile_findPRFDev($aszDev);
- return "" if (!defined($device));
-
- my $iconName = AttrVal($device, "icon", "edit_settings");
-
- my $editIcon = FW_iconName($iconName) ? FW_makeImage($iconName,$iconName,"icon") : "";
- my $script = '<script type="text/javascript">';
- $script.= "function jump_edit_weekprofile_$aszDev() {";
- $script.= "window.location.assign('$FW_ME?cmd={weekprofile_editOnNewpage(";
- $script.= "\"$device\",\"$prf\");;}')};";
- $script.= "</script>";
-
- my $lnk = "$script<a onclick=\"jump_edit_weekprofile_$aszDev()\" href=\"javascript:void(0)\">$editIcon</a>";
- return ($lnk,0);
- }
- 1;
- =pod
- =item summary administration of weekprofiles
- =item summary_DE Verwaltung von Wochenprofilen
- =item helper
- =begin html
- <a name="weekprofile"></a>
- <h3>weekprofile</h3>
- <ul>
- With this module you can manage and edit different weekprofiles. You can send the profiles to different devices.<br>
- Currently the following devices will by supported:<br>
- <li>MAX</li>
- <li>other weekprofile modules</li>
- <li>Homatic channel _Clima or _Climate</li>
-
- In the normal case the module is assoziated with a master device.
- So a profile 'master' will be created automatically. This profile corrensponds to the current active
- profile on the master device.
- You can also use this module without a master device. In this case a default profile will be created.
- <br>
- An other use case is the usage of categories 'Topics'.
- To enable the feature the attribute 'useTopics' have to be set.
- Topics are e.q. winter, summer, holidays, party, and so on.
- A topic consists of different week profiles. Normally one profile for each thermostat.
- The connection between the thermostats and the profile is an user attribute 'weekprofile' without the topic name.
- With 'restore_topic' the defined profile in the attribute will be transfered to the thermostat.
- So it is possible to change the topic easily and all thermostats will be updated with the correndponding profile.
- <br><br>
- <b>Attention:</b>
- To transfer a profile to a device it needs a lot of Credits.
- This is not taken into account from this module. So it could be happend that the profile in the module
- and on the device are not equal until the whole profile is transfered completly.
- <br>
- If the maste device is Homatic HM-TC-IT-WM-W-EU then only the first profile (R_P1_...) will be used!
- <br>
- <b>For this module libjson-perl have to be installed</b>
- <br><br>
- <b>Events:</b><br>
- Currently the following event will be created:<br>
- <li>PROFILE_TRANSFERED: if a profile or a part of a profile (changes) is send to a device</li>
- <li>PROFILES_SAVED: the profile are stored in the config file (also if there are no changes)</li>
- <a name="weekprofiledefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> weekprofile [master device]</code><br>
- <br>
- Activate the module with or without an assoziated master device. The master device is an optional parameter.
- With a master device a spezial profile 'master' will be created.<br>
- Special master' profile handling:<br>
- <li>Can't be deleted</li>
- <li>Will be automatically transfered to the master device if it was modified</li>
- <li>Will not be saved</li>
- <br>
- Without a master device a 'default' profile will be created
- </ul>
-
- <a name="weekprofileset"></a>
- <b>Set</b>
- <ul>
- <li>profile_data<br>
- <code>set <name> profile_data <profilename> <json data> </code><br>
- The profile 'profilename' will be changed. The data have to be in json format.
- </li>
- <li>send_to_device<br>
- <code>set <name> send_to_device <profilename> [devices] </code><br>
- 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
- </li>
- <li>copy_profile<br>
- <code>set <name> copy_profile <source> <destination> </code><br>
- Copy from source to destination. The destination will be overwritten
- </li>
- <li>remove_profile<br>
- <code>set <name> remove_profile <profilename> </code><br>
- Delete profile 'profilename'.
- </li>
- <li>reference_profile<br>
- <code>set <name> reference_profile <source> <destination> </code><br>
- Create a reference from destination to source. The destination will be overwritten if it exits.
- </li>
- <li>restore_topic<br>
- <code>set <name> restore_topic <topic></code><br>
- All weekprofiles from the topic will be transfered to the correcponding devices.
- Therefore a user attribute 'weekprofile' with the weekprofile name <b>without the topic name</b> have to exist in the device.
- </li>
- </ul>
-
- <a name="weekprofileget"></a>
- <b>Get</b>
- <ul>
- <li>profile_data<br>
- <code>get <name> profile_data <profilename> </code><br>
- Get the profile data from 'profilename' in json-Format
- </li>
- <li>profile_names<br>
- <code>set <name> profile_names [topicname]</code><br>
- Get a comma seperated list of weekprofile profile names from the topic 'topicname'
- If topicname is not set, 'default' will be used
- If topicname is '*', all weekprofile profile names are returned.
- </li>
- <li>profile_references [name]<br>
- If name is '*', a comma seperated list of all references in the following syntax
- <code>ref_topic:ref_profile>dest_topic:dest_profile</code>
- are returned
- If name is 'topicname:profilename', '0' or the reference name is returned.
- </li>
- <li>topic_names<br>
- Return a comma seperated list of topic names.
- </li>
- </ul>
-
- <a name="weekprofilereadings"></a>
- <p><b>Readings</b></p>
- <ul>
- <li>active_topic<br>
- Active\last restored topic name
- </li>
- <li>profile_count<br>
- Count of all profiles including references.
- </li>
- </ul>
-
- <a name="weekprofileattr"></a>
- <b>Attributes</b>
- <ul>
- <li>widgetTranslations<br>
- Comma seperated list of texts translations <german>:<translation>
- <code>attr name widgetTranslations Abbrechen:Cancel,Speichern:Save</code>
- </li>
- <li>widgetWeekdays<br>
- Comma seperated list of week days starting at Monday
- <code>attr name widgetWeekdays Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday</code>
- </li>
- <li>widgetEditOnNewPage<br>
- Editing the profile on a new html page if it is set to '1'
- </li>
- <li>widgetEditDaysInRow<br>
- Count of visible days in on row during Edit. Default 2.<br>
- </li>
- <li>configFile<br>
- Path and filename of the configuration file where the profiles will be stored
- Default: ./log/weekprofile-<name>.cfg
- </li>
- <li>icon<br>
- icon for edit<br>
- Default: edit_settings
- </li>
- <li>useTopics<br>
- Enable topics.<br>
- Default: 0
- </li>
- <li>tempON<br>
- Temperature for 'on'. e.g. 30
- </li>
- <li>tempOFF<br>
- Temperature for 'off'. e.g. 4
- </li>
- </ul>
-
- </ul>
- =end html
- =begin html_DE
- <a name="weekprofile"></a>
- <h3>weekprofile</h3>
- <ul>
- Beschreibung im Wiki: http://www.fhemwiki.de/wiki/Weekprofile
-
- Mit dem Modul 'weekprofile' können mehrere Wochenprofile verwaltet und an unterschiedliche Geräte
- übertragen werden. Aktuell wird folgende Hardware unterstützt:
- <li>alle MAX Thermostate</li>
- <li>andere weekprofile Module</li>
- <li>Homatic (Kanal _Clima bzw. _Climate)</li>
-
- Im Standardfall wird das Modul mit einem Geräte = 'Master-Gerät' assoziiert,
- um das Wochenprofil vom Gerät grafisch bearbeiten zu können und andere Profile auf das Gerät zu übertragen.
- Wird kein 'Master-Gerät' angegeben, wird erstmalig ein Default-Profil angelegt.
- <br>
- Ein weiterer Anwendungsfall ist die Verwendung von Rubriken\Kategorien 'Topics'.
- Hier sollte kein 'Master-Gerät' angegeben werden. Dieses Feature muss erst über das Attribut 'useTopics' aktiviert werden.
- Topics sind z.B. Winter, Sommer, Urlaub, Party, etc.
- Innerhalb einer Topic kann es mehrere Wochenprofile geben. Sinnvollerweise sollten es soviele wie Thermostate sein.
- Über ein Userattribut 'weekprofile' im Thermostat wird ein Wochenprofile ohne Topicname angegeben.
- Mittels 'restore_topic' wird dann das angebene Wochenprofil der Topic an das Thermostat übertragen.
- Somit kann man einfach zwischen den Topics wechseln und die Thermostate bekommen das passende Wochenprofil.
- <br><br>
- <b>Achtung:</b> Das Übertragen von Wochenprofilen erfordet eine Menge an Credits.
- Dies wird vom Modul nicht berücksichtigt. So kann es sein, dass nach dem
- Setzen\Aktualisieren eines Profils das Profil im Modul nicht mit dem Profil im Gerät
- übereinstimmt solange das komplette Profil übertragen wurde.
- <br>
- Beim Homatic HM-TC-IT-WM-W-EU wird nur das 1. Profil (R_P1_...) genommen!
- <br>
- <b>Für das Module wird libjson-perl benötigt</b>
- <br><br>
- <b>Events:</b><br>
- Aktuell werden folgende Events erzeugt:<br>
- <li>PROFILE_TRANSFERED: wenn ein Profil oder Teile davon zu einem Gerät gesended wurden</li>
- <li>PROFILES_SAVED: wenn Profile in die Konfigurationsdatei gespeichert wurden (auch wenn es keine Änderung gab!)</li>
- <a name="weekprofiledefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> weekprofile [master device]</code><br>
- <br>
- Aktiviert das Modul. Bei der Angabe eines 'Master-Gerätes' wird das Profil 'master'
- entprechende dem Wochenrofil vom Gerät angelegt.
- Sonderbehandlung des 'master' Profils:
- <li>Kann nicht gelöscht werden</li>
- <li>Bei Ändern\Setzen des Proils wird es automatisch an das 'Master-Geräte' gesendet</li>
- <li>Es wird sind mit abgespeicht</li>
- <br>
- Wird kein 'Master-Geräte' angegeben, wird ein 'default' Profil angelegt.
- </ul>
-
- <a name="weekprofileset"></a>
- <b>Set</b>
- <ul>
- <li>profile_data<br>
- <code>set <name> profile_data <profilname> <json data> </code><br>
- Es wird das Profil 'profilname' geändert. Die Profildaten müssen im json-Format übergeben werden.
- </li>
- <li>send_to_device<br>
- <code>set <name> send_to_device <profilname> [devices] </code><br>
- 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
- </li>
- <li>copy_profile<br>
- <code>set <name> copy_profile <quelle> <ziel> </code><br>
- Kopiert das Profil 'quelle' auf 'ziel'. 'ziel' wird überschrieben oder neu angelegt.
- </li>
- <li>remove_profile<br>
- <code>set <name> remove_profile <profilname> </code><br>
- Das Profil 'profilname' wird gelöscht.
- </li>
- <li>reference_profile<br>
- <code>set <name> reference_profile <quelle> <ziel> </code><br>
- Referenziert das Profil 'ziel'auf 'quelle'. 'ziel' wird überschrieben oder neu angelegt.
- </li>
- <li>restore_topic<br>
- <code>set <name> restore_topic <topic></code><br>
- Alle Wochenpläne in der Topic werden zu den entsprechenden Geräten übertragen.
- Dazu muss im Gerät ein Userattribut 'weekprofile' mit dem Namen des Wochenplans <b>ohne</b> Topic gesetzt sein.
- </li>
- </ul>
-
- <a name="weekprofileget"></a>
- <b>Get</b>
- <ul>
- <li>profile_data<br>
- <code>get <name> profile_data <profilname> </code><br>
- Liefert die Profildaten von 'profilname' im json-Format
- </li>
- <li>profile_names<br>
- <code>set <name> profile_names [topic_name]</code><br>
- Liefert alle Profilnamen getrennt durch ',' einer Topic 'topic_name'
- Ist 'topic_name' gleich '*' werden alle Profilnamen zurück gegeben.
- </li>
- <li>profile_references [name]<br>
- Liefert eine Liste von Referenzen der Form <br>
- <code>
- ref_topic:ref_profile>dest_topic:dest_profile
- </code>
- Ist name 'topicname:profilename' wird '0' der Name der Referenz zurück gegeben.
- </li>
- </ul>
-
- <a name="weekprofilereadings"></a>
- <p><b>Readings</b></p>
- <ul>
- <li>active_topic<br>
- Aktive\zuletzt gesetzter Topicname.
- </li>
- <li>profile_count<br>
- Anzahl aller Profile mit Referenzen.
- </li>
- </ul>
-
- <a name="weekprofileattr"></a>
- <b>Attribute</b>
- <ul>
- <li>widgetTranslations<br>
- Liste von Übersetzungen der Form <german>:<Übersetzung> getrennt durch ',' um Texte im Widget zu übersetzen.
- <code>attr name widgetTranslations Abbrechen:Abbr,Speichern:Save</code>
- </li>
- <li>widgetWeekdays<br>
- Liste von Wochentagen getrennt durch ',' welche im Widget angzeigt werden.
- Beginnend bei Montag. z.B.
- <code>attr name widgetWeekdays Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag</code>
- </li>
- <li>widgetEditDaysInRow<br>
- Anzahl in der in einer Reihe dargestellten Tage während der Bearbeitung. Default 2.<br>
- </li>
- <li>widgetEditOnNewPage<br>
- Wenn gesetzt ('1'), dann wird die Bearbeitung auf einer separaten\neuen Webseite gestartet.
- </li>
- <li>configFile<br>
- Pfad und Dateiname wo die Profile gespeichert werden sollen.
- Default: ./log/weekprofile-<name>.cfg
- </li>
- <li>icon<br>
- Änders des Icons zum Bearbeiten
- Default: edit_settings
- </li>
- <li>useTopics<br>
- Verwendung von Topic aktivieren.
- </li>
- <li>tempON<br>
- Temperature für 'on'. z.B. 30
- </li>
- <li>tempOFF<br>
- Temperature für 'off'. z.B. 4
- </li>
- </ul>
-
- </ul>
- =end html_DE
- =cut
|