new module 31_LightScene to save and restore the state of a group of lights and other actors

git-svn-id: https://fhem.svn.sourceforge.net/svnroot/fhem/trunk/fhem@2935 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
justme1968
2013-03-17 09:39:50 +00:00
parent c7d511fb6a
commit 03bf8e7c2e
2 changed files with 311 additions and 2 deletions

View File

@@ -1,6 +1,8 @@
# Add changes at the top of the list. # Add changes at the top of the list.
- SVN - SVN
- feature: new module 31_LightScene to save and restore the state of a
group of lights and other actors
- feature: VIERA module added (by teevau) - feature: VIERA module added (by teevau)
- change: FHEMWEB: the first webCmd argument is no longer used by the - change: FHEMWEB: the first webCmd argument is no longer used by the
state-icon, this can be implemented by the new devStateIcon state-icon, this can be implemented by the new devStateIcon
@@ -12,11 +14,11 @@
- feature: added example Setup SQL and configuration for SQLite - feature: added example Setup SQL and configuration for SQLite
- change: modified MySQL Setup SQL to use 512 characters in EVENT column - change: modified MySQL Setup SQL to use 512 characters in EVENT column
- feature: added new Javascript Frontend based on ExtJS (by Johannes) - feature: added new Javascript Frontend based on ExtJS (by Johannes)
- feature: new Modules 30_HUEBridge and 31_HUEDevice for phillips hue and - feature: new modules 30_HUEBridge and 31_HUEDevice for phillips hue and
smartlink devices (by justme1968) smartlink devices (by justme1968)
- change: SYSSTAT: allow remote monitoring by ssh - change: SYSSTAT: allow remote monitoring by ssh
- change: SYSSTAT: allow less frequent updates for diskusage - change: SYSSTAT: allow less frequent updates for diskusage
- feature: new Module 32_SYSSTAT to monitor system load and disk usage - feature: new module 32_SYSSTAT to monitor system load and disk usage
on linux FHEM hosts (by justme1968) on linux FHEM hosts (by justme1968)
- feature: new Module 73_PRESENCE to make automatic presence detection of - feature: new Module 73_PRESENCE to make automatic presence detection of
mobile phones or other mobile devices (like tablets) via ping or mobile phones or other mobile devices (like tablets) via ping or

307
FHEM/31_LightScene.pm Normal file
View File

@@ -0,0 +1,307 @@
package main;
use strict;
use warnings;
use POSIX;
use JSON::XS;
sub LightScene_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "LightScene_Define";
$hash->{NotifyFn} = "LightScene_Notify";
$hash->{UndefFn} = "LightScene_Undefine";
$hash->{SetFn} = "LightScene_Set";
$hash->{GetFn} = "LightScene_Get";
}
sub LightScene_Define($$)
{
my ($hash, $def) = @_;
my @args = split("[ \t]+", $def);
return "Usage: define <name> LightScene <device>+" if(@args < 3);
my $name = shift(@args);
my $tyoe = shift(@args);
my %list;
foreach my $a (@args) {
foreach my $d (devspec2array($a)) {
$list{$d} = 1;
}
}
$hash->{CONTENT} = \%list;
my %scenes;
$hash->{SCENES} = \%scenes;
LightScene_Load($hash);
$hash->{STATE} = 'Initialized';
return undef;
}
sub LightScene_Undefine($$)
{
my ($hash,$arg) = @_;
LightScene_Save();
return undef;
}
sub
LightScene_Notify($$)
{
my ($hash,$dev) = @_;
my $name = $hash->{NAME};
my $type = $hash->{TYPE};
return if($dev->{NAME} ne "global");
if( grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}) ) {
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
LightScene_Save();
}
return undef;
}
sub
myStatefileName()
{
my $statefile = $attr{global}{statefile};
$statefile = substr $statefile,0,rindex($statefile,'/')+1;
return $statefile ."LightScenes.save";
}
my $LightScene_LastSaveTime="";
sub
LightScene_Save()
{
my $time_now = TimeNow();
return if( $time_now eq $LightScene_LastSaveTime);
$LightScene_LastSaveTime = $time_now ;
return "No statefile specified" if(!$attr{global}{statefile});
my $statefile = myStatefileName();
my $hash;
for my $d (keys %defs) {
next if($defs{$d}{TYPE} ne "LightScene");
next if( !defined($defs{$d}{SCENES}) );
$hash->{$d} = $defs{$d}{SCENES} if( keys(%{$defs{$d}{SCENES}}) );
}
if(open(FH, ">$statefile")) {
my $t = localtime;
print FH "#$t\n";
print FH encode_json($hash) if( defined($hash) );
close(FH);
} else {
my $msg = "LightScene_Save: Cannot open $statefile: $!";
Log 1, $msg;
}
return undef;
}
sub
LightScene_Load($)
{
my ($hash) = @_;
return "No statefile specified" if(!$attr{global}{statefile});
my $statefile = myStatefileName();
if(open(FH, "<$statefile")) {
my $json;
while (my $line = <FH>) {
chomp $line;
next if($line =~ m/^#.*$/);
$json .= $line;
}
close(FH);
return if( !defined($json) );
my $decoded = decode_json( $json );
if( defined($decoded->{$hash->{NAME}}) ) {
$hash->{SCENES} = $decoded->{$hash->{NAME}};
}
} else {
my $msg = "LightScene_Load: Cannot open $statefile: $!";
Log 1, $msg;
}
return undef;
}
sub
LightScene_Set($@)
{
my ($hash, $name, $cmd, $value, @a) = @_;
my $ret = "";
if( !defined($cmd) ){ return "$name: set needs at least one parameter" };
if( $cmd eq "?" ){ return "Unknown argument ?, choose one of save scene:".join(",", sort keys %{$hash->{SCENES}}) };
if( $cmd eq "save" && !defined( $value ) ) { return "Usage: set save <scene_name>" };
if( $cmd eq "scene" && !defined( $value ) ) { return "Usage: set scene <scene_name>" };
if( $cmd eq "remove" && !defined( $value ) ) { return "Usage: set remove <scene_name>" };
if( $cmd eq "remove" ) {
delete( $hash->{SCENES}{$value} );
return undef;
};
$hash->{INSET} = 1;
foreach my $d (sort keys %{ $hash->{CONTENT} }) {
next if(!$defs{$d});
if($defs{$d}{INSET}) {
Log 1, "ERROR: endless loop detected for $d in " . $hash->{NAME};
next;
}
if( $cmd eq "save" ) {
my $status = "";
if( $defs{$d}{TYPE} eq 'CUL_HM' ) {
my $subtype = AttrVal($d,"subType","");
if( $subtype eq "switch" ) {
$status = Value($d);
} elsif( $subtype eq "dimmer" ) {
$status = Value($d);
}
} elsif( $defs{$d}{TYPE} eq 'FS20' ) {
$status = Value($d);
} elsif( $defs{$d}{TYPE} eq 'HUEDevice' ) {
my $subtype = AttrVal($d,"subType","");
if( $subtype eq "switch" || Value($d) eq "off" ) {
$status = Value($d);
} elsif( $subtype eq "dimmer" ) {
$status = "bri ". ReadingsVal($d,'bri',"0");
} elsif( $subtype eq "colordimmer" ) {
$status = "bri ". ReadingsVal($d,'bri',"0") ." : xy ". ReadingsVal($d,'xy',"");
}
} elsif( $defs{$d}{TYPE} eq 'IT' ) {
my $subtype = AttrVal($d,"model","");
if( $subtype eq "itswitch" ) {
$status = Value($d);
} elsif( $subtype eq "itdimmer" ) {
$status = Value($d);
}
} elsif( $defs{$d}{TYPE} eq 'TRX_LIGHT' ) {
$status = Value($d);
} else {
$status = Value($d);
}
$hash->{SCENES}{$value}{$d} = $status;
$ret .= $d .": ". $status ."\n";
} elsif ( $cmd eq "scene" ) {
$hash->{STATE} = $value;
$ret .= " ". CommandSet(undef,"$d $hash->{SCENES}{$value}{$d}");
} else {
$ret = "Unknown argument $cmd, choose one of save scene";
}
}
delete($hash->{INSET});
Log GetLogLevel($hash->{NAME},5), "SET: $ret" if($ret);
return $ret;
return undef;
}
sub
LightScene_Get($@)
{
my ($hash, @a) = @_;
my $name = $a[0];
return "$name: get needs at least one parameter" if(@a < 2);
my $cmd= $a[1];
if( $cmd eq "scene" && @a < 3 ) { return "Usage: get scene <scene_name>" };
my $ret = "";
if( $cmd eq "scenes" ) {
foreach my $scene (sort keys %{ $hash->{SCENES} }) {
$ret .= $scene ."\n";
}
return $ret;
} elsif( $cmd eq "scene" ) {
my $ret = "";
my $scene = $a[2];
if( defined($hash->{SCENES}{$scene}) ) {
foreach my $device (sort keys %{ $hash->{SCENES}{$scene} }) {
$ret .= $device .": ". $hash->{SCENES}{$scene}{$device} ."\n";
}
} else {
$ret = "no scene <$scene> defined";
}
return $ret;
}
return "Unknown argument $cmd, choose one of scenes scene";
}
1;
=pod
=begin html
<a name="LightScene"></a>
<h3>LightScene</h3>
<ul>
Allows to store the state of a group of lights and recall it later. Multiple states for one group can be stored.
<br><br>
<a name="LightScene_Define"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; LightScene [&lt;dev1&gt;] [&lt;dev2&gt;] [&lt;dev3&gt;] ... </code><br>
<br>
Examples:
<ul>
<code>define light_group LightScene Lampe1 Lampe2 Dimmer1</code><br>
</ul>
</ul><br>
<a name="LightScene_Set"></a>
<b>Set</b>
<ul>
<li>save &lt;scene_name&gt;<br>
save current state for alle devices in this LightScene to &lt;scene_name&gt;</li>
<li>scene &lt;scene_name&gt;<br>
shows scene &lt;scene_name&gt; - all devices are switched to the previously saved state</li>
<li>remove &lt;scene_name&gt;<br>
remove &lt;scene_name&gt; from list of saved scenes</li>
</ul><br>
<a name="LightScene_Get"></a>
<b>Get</b>
<ul>
<li>scenes</li>
<li>scene &lt;scene_name&gt;</li>
</ul><br>
</ul><br>
=end html
=cut