mirror of
https://github.com/fhem/fhem-mirror.git
synced 2024-11-22 16:09:49 +00:00
386 lines
11 KiB
Perl
386 lines
11 KiB
Perl
|
###################LoTT Uniroll###################
|
|||
|
# UNIRoll:no synchronisation, the message protocoll begins directly with datas
|
|||
|
# group address 16 Bit like an housecode
|
|||
|
# channel address 4 Bit up to 16 devices
|
|||
|
# command 4 Bit up: E(1110),stop: D(1101), down: B(1011)
|
|||
|
# end off 1 Bit, zero or one it doesnot matter
|
|||
|
# whole length 25 Bit
|
|||
|
#time intervall:
|
|||
|
#Bit-digit 0 high ca. 1,6 ms equal 100(h64) 16us steps
|
|||
|
# low ca. 0,576 ms 36(h24)
|
|||
|
#Bit-digit 1 high ca. 0,576 ms 36(h24)
|
|||
|
# low ca. 1,6 ms 100(h64)
|
|||
|
#timespace ca. 100 ms
|
|||
|
#binary : 1010 1011 1100 1101 0110 1110 1
|
|||
|
#hexa: a b c d 6 e 8 (an additional one bit)
|
|||
|
#the message is sent with the general cul-command: G
|
|||
|
#G0031A364242464abcd6e8 : 00 synchbits 3 databytes, 1 databit, HHLLLLHH, data
|
|||
|
|
|||
|
package main;
|
|||
|
|
|||
|
use strict;
|
|||
|
use warnings;
|
|||
|
|
|||
|
my %codes = (
|
|||
|
"e" => "up", #1110 e
|
|||
|
"d" => "stop", #1101 d
|
|||
|
"b" => "down", #1011 b
|
|||
|
);
|
|||
|
|
|||
|
my %readonly = (
|
|||
|
"thermo-on" => 1,
|
|||
|
"thermo-off" => 1,
|
|||
|
);
|
|||
|
|
|||
|
use vars qw(%UNIRoll_c2b); # Peter would like to access it from outside
|
|||
|
|
|||
|
my $UNIRoll_simple ="off off-for-timer on on-for-timer on-till reset timer toggle";
|
|||
|
|
|||
|
my %models = (
|
|||
|
R_23700 => 'simple',
|
|||
|
dummySimple => 'simple',
|
|||
|
);
|
|||
|
|
|||
|
sub hex2fouru($);
|
|||
|
sub four2hexu($$);
|
|||
|
|
|||
|
sub
|
|||
|
UNIRoll_Initialize($)
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
my ($hash) = @_;
|
|||
|
|
|||
|
foreach my $k (keys %codes) {
|
|||
|
$UNIRoll_c2b{$codes{$k}} = $k; # c2b liest das allgmeine Array der Ger<65>tegruppe
|
|||
|
}
|
|||
|
# print "UNIRoll_Initialize \n";
|
|||
|
$hash->{Match} = "^G.*";
|
|||
|
$hash->{SetFn} = "UNIRoll_Set";
|
|||
|
$hash->{StateFn} = "UNIRoll_SetState";
|
|||
|
$hash->{DefFn} = "UNIRoll_Define";
|
|||
|
$hash->{UndefFn} = "UNIRoll_Undef";
|
|||
|
$hash->{ParseFn} = "UNIRoll_Parse";
|
|||
|
$hash->{AttrList} = "IODev do_not_notify:1,0 ".
|
|||
|
"ignore:1,0 showtime:1,0 ".
|
|||
|
"loglevel:0,1,2,3,4,5,6 " .
|
|||
|
"model:".join(",", sort keys %models);
|
|||
|
}
|
|||
|
|
|||
|
#####################################
|
|||
|
sub
|
|||
|
UNIRoll_SetState($$$$) # 4 Skalare Parameter
|
|||
|
|
|||
|
{
|
|||
|
my ($hash, $tim, $vt, $val) = @_; #@_ Array
|
|||
|
# print "UNIRoll_SetState \n";
|
|||
|
|
|||
|
$val = $1 if($val =~ m/^(.*) \d+$/); # m match Funktion
|
|||
|
my $name = $hash->{NAME};
|
|||
|
(undef, $val) = ReplaceEventMap($name, [$name, $val], 0)
|
|||
|
if($attr{$name}{eventMap});
|
|||
|
return "setstate $name: undefined value $val" if(!defined($UNIRoll_c2b{$val}));
|
|||
|
return undef;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
###################################
|
|||
|
sub
|
|||
|
UNIRoll_Set($@)
|
|||
|
|
|||
|
{
|
|||
|
my ($hash, @a) = @_; # Eingabewerte nach define name typ devicecode channelcode
|
|||
|
my $ret = undef;
|
|||
|
my $na = int(@a); #na Anzahl Felder in a
|
|||
|
# print "UNIRoll_Set \n";
|
|||
|
return "no set value specified" if($na < 2 || $na > 3);
|
|||
|
return "Readonly value $a[1]" if(defined($readonly{$a[1]}));
|
|||
|
|
|||
|
my $c = $UNIRoll_c2b{$a[1]}; # Wert des Kommandos: up stop down
|
|||
|
my $name = $a[0]; # Ger<65>tename
|
|||
|
if(!defined($c)) {
|
|||
|
|
|||
|
# Model specific set arguments
|
|||
|
if(defined($attr{$name}) && defined($attr{$name}{"model"})) {
|
|||
|
my $mt = $models{$attr{$name}{"model"}};
|
|||
|
return "Unknown argument $a[1], choose one of "
|
|||
|
if($mt && $mt eq "sender");
|
|||
|
return "Unknown argument $a[1], choose one of $UNIRoll_simple"
|
|||
|
if($mt && $mt eq "simple");
|
|||
|
}
|
|||
|
return "Unknown argument $a[1], choose one of " .
|
|||
|
join(" ", sort keys %UNIRoll_c2b);
|
|||
|
}
|
|||
|
|
|||
|
my $v = join(" ", @a);
|
|||
|
Log GetLogLevel($name,2), "UNIRoll set $v";
|
|||
|
(undef, $v) = split(" ", $v, 2); # Not interested in the name...
|
|||
|
|
|||
|
my $val;
|
|||
|
|
|||
|
# G0030A364242464abcd6e8 : 00 Synchbits 3 Datenbytes, 1 Datenbit, HHLLLLHH, Daten
|
|||
|
# Damit kein Befehl einen zuf<75>lligen Betrieb stoppt
|
|||
|
# vorher ein gezielter Stopp Befehl
|
|||
|
my $stop = "d";
|
|||
|
IOWrite($hash, "","G0030A364242464".$hash->{XMIT}.$hash->{BTN}.$stop);
|
|||
|
# print "$hash XMIT:$hash->{XMIT} BTN: $hash->{BTN} c: $c \n";
|
|||
|
IOWrite($hash, "","G0030A364242464".$hash->{XMIT}.$hash->{BTN}.$c);
|
|||
|
# XMIT: Ger<65>tegruppe, BTN: Kanalnummer, c: Commando
|
|||
|
|
|||
|
|
|||
|
|
|||
|
###########################################
|
|||
|
# Set the state of a device to off if on-for-timer is called
|
|||
|
if($modules{UNIRoll}{ldata}{$name}) {
|
|||
|
CommandDelete(undef, $name . "_timer");
|
|||
|
delete $modules{UNIRoll}{ldata}{$name};
|
|||
|
}
|
|||
|
if($a[1] =~ m/for-timer/ && $na == 3 &&
|
|||
|
defined($attr{$name}) && defined($attr{$name}{"follow-on-for-timer"})) {
|
|||
|
my $to = sprintf("%02d:%02d:%02d", $val/3600, ($val%3600)/60, $val%60);
|
|||
|
$modules{UNIRoll}{ldata}{$name} = $to;
|
|||
|
Log 4, "Follow: +$to setstate $name off";
|
|||
|
CommandDefine(undef,
|
|||
|
$name."_timer at +$to setstate $name off; trigger $name off");
|
|||
|
}
|
|||
|
|
|||
|
##########################
|
|||
|
# Look for all devices with the same code, and set state, timestamp
|
|||
|
my $code = "$hash->{XMIT} $hash->{BTN}";
|
|||
|
my $tn = TimeNow();
|
|||
|
my $defptr = $modules{UNIRoll}{defptr};
|
|||
|
foreach my $n (keys %{ $defptr->{$code} }) {
|
|||
|
my $lh = $defptr->{$code}{$n};
|
|||
|
$lh->{CHANGED}[0] = $v;
|
|||
|
$lh->{STATE} = $v;
|
|||
|
$lh->{READINGS}{state}{TIME} = $tn;
|
|||
|
$lh->{READINGS}{state}{VAL} = $v;
|
|||
|
my $lhname = $lh->{NAME};
|
|||
|
if($name ne $lhname) {
|
|||
|
DoTrigger($lhname, undef);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return $ret;
|
|||
|
}
|
|||
|
|
|||
|
#############################
|
|||
|
|
|||
|
sub
|
|||
|
UNIRoll_Define($$)
|
|||
|
|
|||
|
|
|||
|
# Ger<65>t anmelden hash: Hash-adresse, def: Eingabe bei define .....
|
|||
|
# Hauscode, Kanalnummer aufbereiten pr<70>fen
|
|||
|
{
|
|||
|
my ($hash, $def) = @_;
|
|||
|
my @a = split("[ \t][ \t]*", $def);
|
|||
|
my $u = "wrong syntax: define <name> UNIRoll device adress " .
|
|||
|
"addr [fg addr] [lm addr] [gm FF]";
|
|||
|
# print "UNIRoll_Define \n";
|
|||
|
|
|||
|
return $u if(int(@a) < 4);
|
|||
|
return "Define $a[0]: wrong device address format: specify a 4 digit hex value ".
|
|||
|
"or an 8 digit quad value"
|
|||
|
if( ($a[2] !~ m/^[a-f0-9]{4}$/i) && ($a[2] !~ m/^[1-4]{8}$/i) );
|
|||
|
|
|||
|
return "Define $a[0]: wrong chanal format: specify a 1 digit hex value " .
|
|||
|
"or a 2 digit quad value"
|
|||
|
if( ($a[3] !~ m/^[a-f0-9]{1}$/i) && ($a[3] !~ m/^[1-4]{2}$/i) );
|
|||
|
|
|||
|
my $devcode = $a[2];
|
|||
|
$devcode = four2hexu($devcode,4) if (length($devcode) == 8);
|
|||
|
|
|||
|
my $chacode = $a[3];
|
|||
|
$chacode = four2hexu($chacode,2) if (length($chacode) == 4);
|
|||
|
|
|||
|
$hash->{XMIT} = lc($devcode); # hex Kleinschreibung ?
|
|||
|
$hash->{BTN} = lc($chacode);
|
|||
|
|
|||
|
# Ger<65>tedaten aufbauen,
|
|||
|
# defptr: device pointer global
|
|||
|
|
|||
|
my $code = lc("$devcode $chacode"); #lc lowercase Kleinschreibung
|
|||
|
my $ncode = 1; #?
|
|||
|
my $name = $a[0]; #Ger<65>tename
|
|||
|
$hash->{CODE}{$ncode++} = $code;
|
|||
|
$modules{UNIRoll}{defptr}{$code}{$name} = $hash;
|
|||
|
|
|||
|
# print "Test IoPort $hash def $def code $code.\n";
|
|||
|
|
|||
|
AssignIoPort($hash); # Ger<65>t anmelden
|
|||
|
}
|
|||
|
|
|||
|
#############################
|
|||
|
sub
|
|||
|
UNIRoll_Undef($$)
|
|||
|
|
|||
|
{
|
|||
|
my ($hash, $name) = @_;
|
|||
|
|
|||
|
foreach my $c (keys %{ $hash->{CODE} } ) {
|
|||
|
$c = $hash->{CODE}{$c};
|
|||
|
# print "UNIRoll_Undef \n";
|
|||
|
# As after a rename the $name my be different from the $defptr{$c}{$n}
|
|||
|
# we look for the hash.
|
|||
|
foreach my $dname (keys %{ $modules{UNIRoll}{defptr}{$c} }) {
|
|||
|
delete($modules{UNIRoll}{defptr}{$c}{$dname})
|
|||
|
if($modules{UNIRoll}{defptr}{$c}{$dname} == $hash);
|
|||
|
}
|
|||
|
}
|
|||
|
return undef;
|
|||
|
}
|
|||
|
|
|||
|
sub
|
|||
|
UNIRoll_Parse($$)
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
# print "UNIRoll_Parse \n";
|
|||
|
}
|
|||
|
|
|||
|
#############################
|
|||
|
sub
|
|||
|
hex2fouru($)
|
|||
|
{
|
|||
|
my $v = shift;
|
|||
|
my $r = "";
|
|||
|
foreach my $x (split("", $v)) {
|
|||
|
$r .= sprintf("%d%d", (hex($x)/4)+1, (hex($x)%4)+1);
|
|||
|
}
|
|||
|
# print "UNIRoll_hex2fouru $r \n";
|
|||
|
|
|||
|
return $r;
|
|||
|
}
|
|||
|
|
|||
|
#############################
|
|||
|
sub
|
|||
|
four2hexu($$)
|
|||
|
{
|
|||
|
my ($v,$len) = @_;
|
|||
|
my $r = 0;
|
|||
|
foreach my $x (split("", $v)) {
|
|||
|
$r = $r*4+($x-1);
|
|||
|
}
|
|||
|
# print "UNIRoll_fourhex r:$r len: $len\n";
|
|||
|
|
|||
|
return sprintf("%0*x", $len,$r);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
1;
|
|||
|
|
|||
|
|
|||
|
=pod
|
|||
|
=begin html
|
|||
|
|
|||
|
<a name="UNIRoll"></a>
|
|||
|
<h3>UNIRoll</h3>
|
|||
|
<ul>
|
|||
|
The protocol is used by the Lott UNIROLL R-23700 reciever. The radio
|
|||
|
(868.35 MHz) messages are either received through an <a href="#FHZ">FHZ</a>
|
|||
|
or an <a href="#CUL">CUL</a> device, so this must be defined first.
|
|||
|
Recieving sender messages is not integrated.
|
|||
|
The CUL have to allow working with zero synchbits on the beginning of a message.
|
|||
|
<br><br>
|
|||
|
|
|||
|
<a name="UNIRolldefine"></a>
|
|||
|
<b>Define</b>
|
|||
|
<ul>
|
|||
|
<code>define <name> UNIRoll <devicegroup> <deviceaddress> </code>
|
|||
|
<br><br>
|
|||
|
|
|||
|
The values of devicegroup addres (similar to the housecode) and device address (button) can be either defined as
|
|||
|
hexadecimal value or as ELV-like "quad-decimal" value with digits 1-4. We
|
|||
|
will reference this ELV-like notation as ELV4 later in this document. You
|
|||
|
may even mix both hexadecimal and ELV4 notations, because FHEM can detect
|
|||
|
the used notation automatically by counting the digits.
|
|||
|
There is no master or group code integrated.
|
|||
|
<br>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><code><devicecode></code> is a 4 digit hex or 8 digit ELV4 number,
|
|||
|
corresponding to the housecode address.</li>
|
|||
|
<li><code><channel></code> is a 1 digit hex or 2 digit ELV4 number,
|
|||
|
corresponding to a button of the transmitter.</li>
|
|||
|
</ul>
|
|||
|
<br>
|
|||
|
|
|||
|
Examples:
|
|||
|
<ul>
|
|||
|
<code>define lamp UNIRoll 7777 0
|
|||
|
<code>define otherlamp UNIRoll 24242424 11
|
|||
|
</ul>
|
|||
|
</ul>
|
|||
|
<br>
|
|||
|
|
|||
|
<a name="UNIRollset"></a>
|
|||
|
<b>Set </b>
|
|||
|
<ul>
|
|||
|
<code>set <name> <value> [<time>]</code>
|
|||
|
<br><br>
|
|||
|
where <code>value</code> is one of:<br>
|
|||
|
<pre>
|
|||
|
up
|
|||
|
stop
|
|||
|
down
|
|||
|
</pre>
|
|||
|
Examples:
|
|||
|
<ul>
|
|||
|
<code>set roll up</code><br>
|
|||
|
<code>set roll1,roll2,roll3 up</code><br>
|
|||
|
<code>set roll1-roll3 up</code><br>
|
|||
|
</ul>
|
|||
|
<br>
|
|||
|
|
|||
|
<b>Get</b> <ul>N/A</ul><br>
|
|||
|
|
|||
|
<a name="UNIRollattr"></a>
|
|||
|
<b>Attributes</b>
|
|||
|
<ul>
|
|||
|
<a name="IODev"></a>
|
|||
|
<li>IODev<br>
|
|||
|
Set the IO or physical device which should be used for sending signals
|
|||
|
for this "logical" device. An example for the physical device is an FHZ
|
|||
|
or a CUL.</li><br>
|
|||
|
|
|||
|
<a name="eventMap"></a>
|
|||
|
<li>eventMap<br>
|
|||
|
Replace event names and set arguments. The value of this attribute
|
|||
|
consists of a list of space separated values, each value is a colon
|
|||
|
separated pair. The first part specifies the "old" value, the second
|
|||
|
the new/desired value. If the first character is slash(/) or komma(,)
|
|||
|
then split not by space but by this character, enabling to embed spaces.
|
|||
|
Examples:<ul><code>
|
|||
|
attr device eventMap up:open down:closed<br>
|
|||
|
set device open
|
|||
|
</code></ul>
|
|||
|
</li><br>
|
|||
|
|
|||
|
<li><a href="#loglevel">loglevel</a></li><br>
|
|||
|
|
|||
|
<li><a href="#showtime">showtime</a></li><br>
|
|||
|
|
|||
|
<a name="model"></a>
|
|||
|
<li>model<br>
|
|||
|
The model attribute denotes the model type of the device.
|
|||
|
The attributes will (currently) not be used by the fhem.pl directly.
|
|||
|
It can be used by e.g. external programs or web interfaces to
|
|||
|
distinguish classes of devices and send the appropriate commands.
|
|||
|
The spelling of the model names are as quoted on the printed
|
|||
|
documentation which comes which each device. This name is used
|
|||
|
without blanks in all lower-case letters. Valid characters should be
|
|||
|
<code>a-z 0-9</code> and <code>-</code> (dash),
|
|||
|
other characters should be ommited. Here is a list of "official"
|
|||
|
devices:<br><br>
|
|||
|
|
|||
|
<b>Receiver/Actor</b>: there is only one reciever: R_23700
|
|||
|
</li><br>
|
|||
|
|
|||
|
</ul>
|
|||
|
<br>
|
|||
|
|
|||
|
|
|||
|
</ul>
|
|||
|
|