| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- ################################################################
- #
- # Copyright notice
- #
- # (c) 2009 Copyright: Kai 'wusel' Siering (wusel+fhem at uu dot org)
- # All rights reserved
- #
- # This code is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # The GNU General Public License can be found at
- # http://www.gnu.org/copyleft/gpl.html.
- # A copy is found in the textfile GPL.txt and important notices to the license
- # from the author is found in LICENSE.txt distributed with these scripts.
- #
- # This script is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # This copyright notice MUST APPEAR in all copies of the script!
- ###############################################
- ###########################
- # 17_SIS_PMS.pm
- # Module for FHEM
- #
- # Contributed by Kai 'wusel' Siering <wusel+fhem@uu.org> in 2010
- # Based in part on work for FHEM by other authors ...
- # $Id: 17_SIS_PMS.pm 2076 2012-11-04 13:49:43Z rudolfkoenig $
- ###########################
- package main;
- use strict;
- use warnings;
- my $SIS_PMS_cmds ="off on on-till off-till toggle";
- sub
- SIS_PMS_Initialize($)
- {
- my ($hash) = @_;
- $hash->{Match} = "^socket ..:..:..:..:.. .+ state o.*";
- $hash->{SetFn} = "SIS_PMS_Set";
- # $hash->{StateFn} = "SIS_PMS_SetState";
- $hash->{DefFn} = "SIS_PMS_Define";
- $hash->{UndefFn} = "SIS_PMS_Undef";
- $hash->{ParseFn} = "SIS_PMS_Parse";
- }
- #############################
- sub
- SIS_PMS_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- my $u = "wrong syntax: define <name> SIS_PMS <serial> <socket>";
- return $u if(int(@a) < 4);
- my $serial = $a[2];
- my $socketnr = $a[3];
- my $name = $a[0];
- my $serialnocolon=$serial;
- $serialnocolon =~ s/:/_/g;
- $modules{SIS_PMS}{defptr}{$name} = $hash;
- $hash->{SERIAL} = $serial;
- $hash->{SOCKET} = $socketnr;
- $hash->{NAME} = $name;
- $modules{SIS_PMS}{defptr}{$serialnocolon . $socketnr} = $hash;
- $hash->{PREV}{STATE} = "undefined";
- AssignIoPort($hash);
- }
- #############################
- sub
- SIS_PMS_Undef($$)
- {
- my ($hash, $name) = @_;
- #
- # foreach my $c (keys %{ $hash->{CODE} } ) {
- # $c = $hash->{CODE}{$c};
- #
- # # As after a rename the $name my be different from the $defptr{$c}{$n}
- # # we look for the hash.
- # foreach my $dname (keys %{ $modules{SIS_PMS}{defptr}{$c} }) {
- # delete($modules{SIS_PMS}{defptr}{$c}{$dname})
- # if($modules{SIS_PMS}{defptr}{$c}{$dname} == $hash);
- # }
- # }
- return undef;
- }
- #############################
- sub
- SIS_PMS_Parse($$)
- {
- my ($hash, $msg) = @_;
- my $serial;
- my $socknr;
- my $sockst;
- my $dummy;
- my $serialnocolon;
-
-
- # Msg format:
- # ^socket ..:..:..:..:.. . state o.*";
- ($dummy, $serial, $socknr, $dummy, $sockst) = split(' ', $msg);
- $serialnocolon=$serial;
- $serialnocolon =~ s/:/_/g;
- my $def = $modules{SIS_PMS}{defptr}{$serialnocolon . $socknr};
- if($def) {
- Log 5, "SIS_PMS: Found device as " . $def->{NAME};
- if($def->{STATE} ne $sockst) {
- $def->{READINGS}{PREVSTATE}{TIME} = TimeNow();
- $def->{READINGS}{PREVSTATE}{VAL} = $def->{STATE};
- Log 3, "SIS_PMS " . $def->{NAME} ." state changed from " . $def->{STATE} . " to $sockst";
- $def->{PREV}{STATE} = $def->{STATE};
- $def->{CHANGED}[0] = $sockst;
- DoTrigger($def->{NAME}, undef);
- }
- $def->{STATE} = $sockst;
- $def->{READINGS}{state}{TIME} = TimeNow();
- $def->{READINGS}{state}{VAL} = $sockst;
- Log 5, "SIS_PMS " . $def->{NAME} ." state $sockst";
- return $def->{NAME};
- } else {
- my $devname=$serial;
-
- $devname =~ s/:/_/g;
- Log 3, "SIS_PMS Unknown device $serial $socknr, please define it";
- if(defined($hash->{TMPLABEL})) {
- $devname=$hash->{TMPLABEL};
- return "UNDEFINED $devname SIS_PMS $serial $socknr";
- } else {
- return "UNDEFINED SIS_PMS_$devname.$socknr SIS_PMS $serial $socknr";
- }
- }
- }
- #############################
- sub
- SIS_PMS_Do_On_Till($@)
- {
- my ($hash, @a) = @_;
- return "Timespec (HH:MM[:SS]) needed for the on-till command" if(@a != 3);
- my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($a[2]);
- return $err if($err);
- my @lt = localtime;
- my $hms_till = sprintf("%02d:%02d:%02d", $hr, $min, $sec);
- my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]);
- if($hms_now ge $hms_till) {
- Log 4, "on-till: won't switch as now ($hms_now) is later than $hms_till";
- return "";
- }
- my @b = ($a[0], "on");
- SIS_PMS_Set($hash, @b);
- my $tname = $hash->{NAME} . "_till";
- CommandDelete(undef, $tname) if($defs{$tname});
- CommandDefine(undef, "$tname at $hms_till set $a[0] off");
- }
- #############################
- sub
- SIS_PMS_Do_Off_Till($@)
- {
- my ($hash, @a) = @_;
- return "Timespec (HH:MM[:SS]) needed for the off-till command" if(@a != 3);
- my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($a[2]);
- return $err if($err);
- my @lt = localtime;
- my $hms_till = sprintf("%02d:%02d:%02d", $hr, $min, $sec);
- my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]);
- if($hms_now ge $hms_till) {
- Log 4, "off-till: won't switch as now ($hms_now) is later than $hms_till";
- return "";
- }
- my @b = ($a[0], "off");
- SIS_PMS_Set($hash, @b);
- my $tname = $hash->{NAME} . "_till";
- CommandDelete(undef, $tname) if($defs{$tname});
- CommandDefine(undef, "$tname at $hms_till set $a[0] on");
- }
- ###################################
- sub
- SIS_PMS_Set($@)
- {
- my ($hash, @a) = @_;
- my $ret = undef;
- my $na = int(@a);
-
- my $what = lc($a[1]);
- return "no set value specified" if($na < 2 || $na > 3);
- my @cmds=split(" ", $SIS_PMS_cmds);
- my $ncmds=int(@cmds);
- my $i;
- my $known_cmd=0;
- for($i=0; $i<$ncmds; $i++) {
- if($cmds[$i] eq $what) {
- $known_cmd++;
- }
- }
- if($known_cmd==0) {
- return "Unknown argument $what, choose one of $SIS_PMS_cmds";
- }
- return SIS_PMS_Do_On_Till($hash, @a) if($a[1] eq "on-till");
- return SIS_PMS_Do_Off_Till($hash, @a) if($a[1] eq "off-till");
- my $prevstate=$hash->{STATE};
- my $currstate=$what;
- if($what eq "toggle") {
- if($prevstate eq "on") {
- $currstate="off";
- } elsif($prevstate eq "off") {
- $currstate="on";
- }
- }
-
- if($prevstate ne $currstate) {
- $hash->{READINGS}{PREVSTATE}{TIME} = TimeNow();
- $hash->{READINGS}{PREVSTATE}{VAL} = $prevstate;
- Log 3, "SIS_PMS " . $hash->{NAME} ." state changed from $prevstate to $currstate";
- $hash->{PREV}{STATE} = $prevstate;
- $hash->{CHANGED}[0] = $currstate;
- $hash->{STATE} = $currstate;
- $hash->{READINGS}{state}{TIME} = TimeNow();
- $hash->{READINGS}{state}{VAL} = $currstate;
- # DoTrigger($hash->{NAME}, undef);
- }
- my $msg;
- $msg=sprintf("%s %s %s", $hash->{SERIAL}, $hash->{SOCKET}, $what);
- IOWrite($hash, $what, $msg);
- return $ret;
- }
- 1;
- =pod
- =begin html
- <a name="SIS_PMS"></a>
- <h3>SIS_PMS</h3>
- <ul>
- This module is responsible for handling the actual sockets (power on,
- power off, toggle) on a "Silver Shield Power Manager", see <a href="#SISPM">SISPM</a>
- for how to define access to one (SIS_PMS stands for "Silver Shield Power Manager Socket").
- <br><br>
- <a name="SIS_PMSdefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> SIS_PMS <serial> <socket></code>
- <br><br>
- To securely distinguish multiple attached Power Manager devices, the
- serial number of those is used. You get these with "sispmctl -s" - or
- just let autocreate define the sockets attached for you.<br>
- <ul>
- <li><code><serial></code> is the serial number of the Power Manager device, see above.</li>
- <li><code><socket></code> is a number between 1 and 4 (for a 4 socket model)</li>
- </ul>
- <br>
- Examples:
- <ul>
- <code>define lamp SIS_PMS 01:02:03:04:05 1</code><br>
- <code>define otherlamp SIS_PMS 01:02:03:04:05 3</code><br>
- <code>define tv SIS_PMS 01:01:38:44:55 1</code>
- </ul>
- </ul>
- <br>
- <a name="SIS_PMSset"></a>
- <b>Set </b>
- <ul>
- <code>set <name> <value> [<time>]</code>
- <br><br>
- where <code>value</code> is one of:<br>
- <pre>
- off
- on
- toggle
- on-till # Special, see the note
- off-till # Special, see the note
- </pre>
- Examples:
- <ul>
- <code>set lamp on</code><br>
- <code>set lamp1,lamp2,lamp3 on</code><br>
- <code>set lamp1-lamp3 on</code><br>
- <code>set hql_lamp on-till 18:45</code><br>
- </ul>
- <br>
- Notes:
- <ul>
- <li>As an external program is used, a noticeable delay may occur.</li>
- <li>*-till requires an absolute time in the "at" format (HH:MM:SS, HH:MM
- or { <perl code> }, where the perl-code returns a time
- specification).
- If the current time is greater than the specified time, then the
- command is ignored, else an "on" or "off" command, respectively, is
- generated, and for the given time an "off"/"on" command is
- scheduleld via the at command.</li>
- </ul>
- </ul>
- <br>
- <b>Get</b> <ul>N/A</ul><br>
- <a name="SIS_PMSattributes"></a>
- <b>Attributes</b>
- <ul>
- <li><a href="#do_not_notify">do_not_notify</a></li><br>
- <a name="attrdummy"></a>
- <li>dummy<br>
- Set the device attribute dummy to define devices which should not
- output any signals. Associated notifys will be executed if the signal
- is received. Used e.g. to react to a code from a sender, but it will
- not actually switch if triggered in the web frontend.
- </li><br>
- <li><a href="#loglevel">loglevel</a></li><br>
- </ul>
- </ul>
- =end html
- =cut
|