mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-14 05:46:35 +00:00
SHC: add support for analog inputs (EnvSensor) and new device RGB_Dimmer
git-svn-id: https://svn.fhem.de/fhem/trunk@6580 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
7d86d6c032
commit
8e5254396b
@ -1,5 +1,7 @@
|
||||
# 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: SHC: support for analog inputs (EnvSensor) and new device
|
||||
RGB_Dimmer added (rr2000)
|
||||
- feature: PRESENCE: MAC address support for mode fritzbox (by Markus M.)
|
||||
- bugfix: PRESENCE: fixing presence detection in mode fritzbox with new
|
||||
Fritz!OS 6.20 (by Markus M.)
|
||||
|
@ -35,13 +35,15 @@ my $parser = new SHC_parser();
|
||||
my %dev_state_icons = (
|
||||
"PowerSwitch" => "on:on:toggle off:off:toggle set.*:light_question:off",
|
||||
"Dimmer" => "on:on off:off set.*:light_question:off",
|
||||
"EnvSensor" => undef
|
||||
"EnvSensor" => undef,
|
||||
"RGB_Dimmer" => undef
|
||||
);
|
||||
|
||||
my %web_cmds = (
|
||||
"PowerSwitch" => "on:off:toggle:statusRequest",
|
||||
"Dimmer" => "on:off:statusRequest",
|
||||
"EnvSensor" => undef
|
||||
"EnvSensor" => undef,
|
||||
"RGB_Dimmer" => undef
|
||||
);
|
||||
|
||||
# Array format: [ reading1, str_format1, reading2, str_format2 ... ]
|
||||
@ -50,12 +52,17 @@ my %web_cmds = (
|
||||
my %dev_state_format = (
|
||||
"PowerSwitch" => ["on", ""],
|
||||
"Dimmer" => ["on", "", "brightness", "B: "],
|
||||
"EnvSensor" => [ # Results in "T: 23.4 H: 27.3 Baro: 978.34 B: 45"
|
||||
"EnvSensor" => [ # Results in "T: 23.4 H: 27.3 Baro: 978.34 B: 45"
|
||||
"temperature", "T: ",
|
||||
"humidity", "H: ",
|
||||
"barometric_pressure", "Baro: ",
|
||||
"brightness", "B: ",
|
||||
"distance", "D: "
|
||||
"distance", "D: ",
|
||||
"dins", "Din: ",
|
||||
"ains", "Ain: "
|
||||
],
|
||||
"RGB_Dimmer" => [
|
||||
"color", "Color: "
|
||||
]
|
||||
);
|
||||
|
||||
@ -71,6 +78,8 @@ my %sets = (
|
||||
# Used from SetExtensions.pm
|
||||
"blink on-for-timer on-till off-for-timer off-till intervals",
|
||||
"EnvSensor" => "",
|
||||
"RGB_Dimmer" => "Color " .
|
||||
"ColorAnimation",
|
||||
"Custom" => "PowerSwitch.SwitchState " .
|
||||
"PowerSwitch.SwitchStateExt " .
|
||||
"Dimmer.Brightness " .
|
||||
@ -82,7 +91,8 @@ my %sets = (
|
||||
my %gets = (
|
||||
"PowerSwitch" => "",
|
||||
"Dimmer" => "",
|
||||
"EnvSensor" => "input:all,1,2,3,4,5,6,7,8 ",
|
||||
"EnvSensor" => "din:all,1,2,3,4,5,6,7,8 ain:all,1,2,3,4,5 ain_volt:1,2,3,4,5",
|
||||
"RGB_Dimmer" => "",
|
||||
"Custom" => ""
|
||||
);
|
||||
|
||||
@ -96,8 +106,11 @@ my %auto_devtype = (
|
||||
"Environment.Brightness" => "EnvSensor",
|
||||
"Environment.Distance" => "EnvSensor",
|
||||
"GPIO.DigitalPin" => "EnvSensor",
|
||||
"GPIO.AnalogPin" => "EnvSensor",
|
||||
"PowerSwitch.SwitchState" => "PowerSwitch",
|
||||
"Dimmer.Brightness" => "Dimmer"
|
||||
"Dimmer.Brightness" => "Dimmer",
|
||||
"Dimmer.Color" => "RGB_Dimmer",
|
||||
"Dimmer.ColorAnimation" => "RGB_Dimmer"
|
||||
);
|
||||
|
||||
sub SHCdev_Parse($$);
|
||||
@ -117,7 +130,7 @@ sub SHCdev_Initialize($)
|
||||
." readonly:1"
|
||||
." forceOn:1"
|
||||
." $readingFnAttributes"
|
||||
." devtype:EnvSensor,Dimmer,PowerSwitch";
|
||||
." devtype:EnvSensor,Dimmer,PowerSwitch,RGB_Dimmer";
|
||||
}
|
||||
|
||||
#####################################
|
||||
@ -241,10 +254,22 @@ sub SHCdev_Parse($$)
|
||||
for (my $i = 0 ; $i < 8 ; $i++) {
|
||||
my $pinx = $parser->getField("On", $i);
|
||||
my $channel = $i + 1;
|
||||
readingsBulkUpdate($rhash, "pin" . $channel, $pinx);
|
||||
readingsBulkUpdate($rhash, "din" . $channel, $pinx);
|
||||
$pins .= $pinx;
|
||||
}
|
||||
readingsBulkUpdate($rhash, "pins", $pins);
|
||||
readingsBulkUpdate($rhash, "dins", $pins);
|
||||
}
|
||||
when ('AnalogPin') {
|
||||
my $pins = "";
|
||||
for (my $i = 0 ; $i < 5 ; $i++) {
|
||||
my $pinx_on = $parser->getField("On", $i);
|
||||
my $pinx_volt = $parser->getField("Voltage", $i);
|
||||
my $channel = $i + 1;
|
||||
readingsBulkUpdate($rhash, "ain" . $channel, $pinx_on);
|
||||
readingsBulkUpdate($rhash, "ain_volt" . $channel, $pinx_volt);
|
||||
$pins .= $pinx_on;
|
||||
}
|
||||
readingsBulkUpdate($rhash, "ains", $pins);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -303,6 +328,22 @@ sub SHCdev_Parse($$)
|
||||
readingsBulkUpdate($rhash, "on", $on);
|
||||
readingsBulkUpdate($rhash, "brightness", $brightness);
|
||||
}
|
||||
when ('Color') {
|
||||
my $color = $parser->getField("Color");
|
||||
readingsBulkUpdate($rhash, "color", $color);
|
||||
}
|
||||
when ('ColorAnimation') {
|
||||
my $repeat = $parser->getField("Repeat");
|
||||
my $autoreverse = $parser->getField("AutoReverse");
|
||||
readingsBulkUpdate($rhash, "repeat", $repeat);
|
||||
readingsBulkUpdate($rhash, "autoreverse", $autoreverse);
|
||||
for (my $i = 0 ; $i < 10 ; $i = $i + 1) {
|
||||
my $time = $parser->getField("Time" , $i);
|
||||
my $color = $parser->getField("Color", $i);
|
||||
readingsBulkUpdate($rhash, "time$i", $time);
|
||||
readingsBulkUpdate($rhash, "color$i", $color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,6 +519,53 @@ sub SHCdev_Set($@)
|
||||
return SetExtensions($hash, "", $name, @aa);
|
||||
}
|
||||
}
|
||||
when ('RGB_Dimmer') {
|
||||
if ($cmd eq 'Color') {
|
||||
#TODO Verify argument values
|
||||
my $color = $arg;
|
||||
|
||||
# DEBUG
|
||||
# Log3 $name, 3, "$name: Color args: $arg, $arg2, $arg3, $arg4";
|
||||
|
||||
readingsSingleUpdate($hash, "state", "set-color:$color", 1);
|
||||
$parser->initPacket("Dimmer", "Color", "SetGet");
|
||||
$parser->setField("Dimmer", "Color", "Color", $color);
|
||||
SHCdev_Send($hash);
|
||||
} elsif ($cmd eq 'ColorAnimation') {
|
||||
#TODO Verify argument values
|
||||
|
||||
$parser->initPacket("Dimmer", "ColorAnimation", "SetGet");
|
||||
$parser->setField("Dimmer", "ColorAnimation", "Repeat", $arg);
|
||||
$parser->setField("Dimmer", "ColorAnimation", "AutoReverse", $arg2);
|
||||
|
||||
my $curtime = 0;
|
||||
my $curcolor = 0;
|
||||
# Iterate over all given command line parameters and set Time and Color
|
||||
# accordingly. Fill the remaining values with zero.
|
||||
for (my $i = 0 ; $i < 10 ; $i = $i + 1) {
|
||||
if (!defined($aa[($i * 2) + 3])) {
|
||||
$curtime = 0;
|
||||
} else {
|
||||
$curtime = $aa[($i * 2) + 3];
|
||||
}
|
||||
if (!defined($aa[($i * 2) + 4])) {
|
||||
$curcolor = 0;
|
||||
} else {
|
||||
$curcolor = $aa[($i * 2) + 4];
|
||||
}
|
||||
|
||||
# DEBUG
|
||||
# Log3 $name, 3, "$name: Nr: $i Time: $curtime Color: $curcolor";
|
||||
|
||||
$parser->setField("Dimmer", "ColorAnimation", "Time" , $curtime, $i);
|
||||
$parser->setField("Dimmer", "ColorAnimation", "Color", $curcolor, $i);
|
||||
}
|
||||
readingsSingleUpdate($hash, "state", "set-coloranimation", 1);
|
||||
SHCdev_Send($hash);
|
||||
} else {
|
||||
return SetExtensions($hash, "", $name, @aa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
@ -505,9 +593,9 @@ sub SHCdev_Get($@)
|
||||
|
||||
given ($devtype) {
|
||||
when ('EnvSensor') {
|
||||
if ($cmd eq 'input') {
|
||||
if ($cmd eq 'din') {
|
||||
if ($arg =~ /[1-8]/) {
|
||||
my $channel = "pin" . $arg;
|
||||
my $channel = "din" . $arg;
|
||||
if ( defined($hash->{READINGS}{$channel})
|
||||
&& defined($hash->{READINGS}{$channel}{VAL}))
|
||||
{
|
||||
@ -517,14 +605,45 @@ sub SHCdev_Get($@)
|
||||
}
|
||||
elsif ($arg eq "all")
|
||||
{
|
||||
if ( defined($hash->{READINGS}{pins})
|
||||
&& defined($hash->{READINGS}{pins}{VAL}))
|
||||
if ( defined($hash->{READINGS}{dins})
|
||||
&& defined($hash->{READINGS}{dins}{VAL}))
|
||||
{
|
||||
return "$name.pins => " . $hash->{READINGS}{pins}{VAL};
|
||||
return "$name.dins => " . $hash->{READINGS}{dins}{VAL};
|
||||
}
|
||||
return "Error: \"input all\" readings not yet available or not supported by device";
|
||||
}
|
||||
}
|
||||
if ($cmd eq 'ain') {
|
||||
if ($arg =~ /[1-5]/) {
|
||||
my $channel = "ain" . $arg;
|
||||
if ( defined($hash->{READINGS}{$channel})
|
||||
&& defined($hash->{READINGS}{$channel}{VAL}))
|
||||
{
|
||||
return "$name.$channel => " . $hash->{READINGS}{$channel}{VAL};
|
||||
}
|
||||
return "Error: \"input " . $channel . "\" readings not yet available or not supported by device";
|
||||
}
|
||||
elsif ($arg eq "all")
|
||||
{
|
||||
if ( defined($hash->{READINGS}{ains})
|
||||
&& defined($hash->{READINGS}{ains}{VAL}))
|
||||
{
|
||||
return "$name.ains => " . $hash->{READINGS}{ains}{VAL};
|
||||
}
|
||||
return "Error: \"input all\" readings not yet available or not supported by device";
|
||||
}
|
||||
}
|
||||
if ($cmd eq 'ain_volt') {
|
||||
if ($arg =~ /[1-5]/) {
|
||||
my $channel = "ain_volt" . $arg;
|
||||
if ( defined($hash->{READINGS}{$channel})
|
||||
&& defined($hash->{READINGS}{$channel}{VAL}))
|
||||
{
|
||||
return "$name.$channel => " . $hash->{READINGS}{$channel}{VAL};
|
||||
}
|
||||
return "Error: \"input " . $channel . "\" readings not yet available or not supported by device";
|
||||
}
|
||||
}
|
||||
|
||||
# This return is required to provide the get commands in the web interface
|
||||
return "Unknown argument $cmd, choose one of " . $gets{$devtype};
|
||||
@ -603,6 +722,16 @@ sub SHCdev_Send($)
|
||||
<li>statusRequest<br>
|
||||
Supported by Dimmer and PowerSwitch.
|
||||
</li><br>
|
||||
<li>Color <ColorNumber><br>
|
||||
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#Dimmer_Color">www.smarthomatic.org</a>
|
||||
The color palette can be found <a href="http://www.smarthomatic.org/devices/rgb_dimmer.html">here</a>
|
||||
Supported by RGB_Dimmer.
|
||||
</li><br>
|
||||
<li>ColorAnimation <Repeat> <AutoReverse> <Time0> <ColorNumber0> <Time1> <ColorNumber1> ... up to 10 time/color pairs<br>
|
||||
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#Dimmer_ColorAnimation">www.smarthomatic.org</a>
|
||||
The color palette can be found <a href="http://www.smarthomatic.org/devices/rgb_dimmer.html">here</a>
|
||||
Supported by RGB_Dimmer.
|
||||
</li><br>
|
||||
<li><a href="#setExtensions"> set extensions</a><br>
|
||||
Supported by Dimmer and PowerSwitch.</li>
|
||||
</ul><br>
|
||||
@ -610,8 +739,22 @@ sub SHCdev_Send($)
|
||||
<a name="SHCdev_Get"></a>
|
||||
<b>Get</b>
|
||||
<ul>
|
||||
<li>input <pin><br>
|
||||
Returns the state of the specified pin for pin = 1..8 or the state of all pins for pin = all.
|
||||
<li>din <pin><br>
|
||||
Returns the state of the specified digital input pin for pin = 1..8. Or the state of all pins for pin = all.
|
||||
Supported by EnvSensor.
|
||||
</li><br>
|
||||
<li>ain <pin><br>
|
||||
Returns the state of the specified analog input pin for pin = 1..5. Or the state of all pins for pin = all.
|
||||
If the voltage of the pin is over the specied trigger threshold) it return 1 otherwise 0.
|
||||
Supported by EnvSensor.
|
||||
</li><br>
|
||||
<li>ain <pin><br>
|
||||
Returns the state of the specified analog input pin for pin = 1..5. Or the state of all pins for pin = all.
|
||||
If the voltage of the pin is over the specied trigger threshold) it return 1 otherwise 0.
|
||||
Supported by EnvSensor.
|
||||
</li><br>
|
||||
<li>ain_volt <pin><br>
|
||||
Returns the voltage of the specified analog input pin for pin = 1..5 in millivolts, ranging from 0 .. 1100 mV.
|
||||
Supported by EnvSensor.
|
||||
</li><br>
|
||||
</ul><br>
|
||||
@ -621,7 +764,7 @@ sub SHCdev_Send($)
|
||||
<ul>
|
||||
<li>devtype<br>
|
||||
The device type determines the command set, default web commands and the
|
||||
default devStateicon. Currently supported are: EnvSensor, Dimmer, PowerSwitch.<br><br>
|
||||
default devStateicon. Currently supported are: EnvSensor, Dimmer, PowerSwitch, RGB_Dimmer.<br><br>
|
||||
|
||||
Note: If the device is not set manually, it will be determined automatically
|
||||
on reception of a device type specific message. For example: If a
|
||||
|
@ -97,6 +97,7 @@ sub setUIntBits($$$$$)
|
||||
# if length is smaller than 8 bits, get the old value from array
|
||||
if ($length_bits < 8) {
|
||||
$b = @$byteArrayRef[$byte];
|
||||
|
||||
$b = clear_bits($b, $bit, $length_bits);
|
||||
}
|
||||
|
||||
@ -111,7 +112,7 @@ sub setUInt($$$$)
|
||||
{
|
||||
my ($byteArrayRef, $offset, $length_bits, $value) = @_;
|
||||
|
||||
my $byte = $offset / 8;
|
||||
my $byte = int($offset / 8);
|
||||
my $bit = $offset % 8;
|
||||
|
||||
# move bits to the left border
|
||||
@ -125,7 +126,7 @@ sub setUInt($$$$)
|
||||
my $len = min($length_bits, 8 - $bit);
|
||||
my $val8 = get_bits($value, $src_start, $len);
|
||||
|
||||
# DEBUG print " Write bits to byte " . $byte . ", dst_start " . $dst_start . ", len " . $len . ", val8 " . $val8 . "\r\n";
|
||||
# DEBUG print " Write value " . $val8 . " (" . $len . " bits) to byte " . $byte . ", dst_start " . $dst_start . "\r\n";
|
||||
|
||||
setUIntBits($byteArrayRef, $byte, $dst_start, $len, $val8);
|
||||
|
||||
@ -137,7 +138,7 @@ sub setUInt($$$$)
|
||||
$val8 = get_bits($value, $src_start, $len);
|
||||
$byte++;
|
||||
|
||||
# DEBUG print " Byte nr. " . $byte . ", src_start " . $src_start . ", len " . $len . ", val8 " . $val8 . "\r\n";
|
||||
# DEBUG print " Write value " . $val8 . " (" . $len . " bits) from src_start " . $src_start . " to byte " . $byte . ", dst_start " . $dst_start . "\r\n";
|
||||
|
||||
setUIntBits($byteArrayRef, $byte, $dst_start, $len, $val8);
|
||||
|
||||
@ -172,9 +173,11 @@ sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $self = {
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_bits => shift,
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_bits => shift,
|
||||
_length => shift,
|
||||
_arrayElementBits => shift
|
||||
};
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
@ -182,16 +185,16 @@ sub new
|
||||
|
||||
sub getValue
|
||||
{
|
||||
my ($self, $byteArrayRef) = @_;
|
||||
my ($self, $byteArrayRef, $index) = @_;
|
||||
|
||||
return SHC_util::getUInt($byteArrayRef, $self->{_offset}, $self->{_bits});
|
||||
return SHC_util::getUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits});
|
||||
}
|
||||
|
||||
sub setValue
|
||||
{
|
||||
my ($self, $byteArrayRef, $value) = @_;
|
||||
my ($self, $byteArrayRef, $value, $index) = @_;
|
||||
|
||||
SHC_util::setUInt($byteArrayRef, $self->{_offset}, $self->{_bits}, $value);
|
||||
SHC_util::setUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits}, $value);
|
||||
}
|
||||
|
||||
# ----------- IntValue class -----------
|
||||
@ -202,9 +205,11 @@ sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $self = {
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_bits => shift,
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_bits => shift,
|
||||
_length => shift,
|
||||
_arrayElementBits => shift
|
||||
};
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
@ -212,16 +217,16 @@ sub new
|
||||
|
||||
sub getValue
|
||||
{
|
||||
my ($self, $byteArrayRef) = @_;
|
||||
my ($self, $byteArrayRef, $index) = @_;
|
||||
|
||||
return SHC_util::getUInt($byteArrayRef, $self->{_offset}, $self->{_bits});
|
||||
return SHC_util::getUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits});
|
||||
}
|
||||
|
||||
sub setValue
|
||||
{
|
||||
my ($self, $byteArrayRef, $value) = @_;
|
||||
my ($self, $byteArrayRef, $value, $index) = @_;
|
||||
|
||||
SHC_util::setUInt($byteArrayRef, $self->{_offset}, $self->{_bits}, $value);
|
||||
SHC_util::setUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits}, $value);
|
||||
}
|
||||
|
||||
# ----------- BoolValue class -----------
|
||||
@ -232,9 +237,10 @@ sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $self = {
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_length => shift,
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_length => shift,
|
||||
_arrayElementBits => shift
|
||||
};
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
@ -244,14 +250,15 @@ sub getValue
|
||||
{
|
||||
my ($self, $byteArrayRef, $index) = @_;
|
||||
|
||||
return SHC_util::getUInt($byteArrayRef, $self->{_offset} + $index, 1) == 1 ? 1 : 0;
|
||||
return SHC_util::getUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, 1) == 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
sub setValue
|
||||
{
|
||||
my ($self, $byteArrayRef, $value) = @_;
|
||||
my ($self, $byteArrayRef, $value, $index) = @_;
|
||||
|
||||
return SHC_util::setUInt($byteArrayRef, $self->{_offset}, 1, $value == 0 ? 0 : 1);
|
||||
return SHC_util::setUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, 1,
|
||||
$value == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
# ----------- EnumValue class -----------
|
||||
@ -265,9 +272,11 @@ sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $self = {
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_bits => shift,
|
||||
_id => shift,
|
||||
_offset => shift,
|
||||
_bits => shift,
|
||||
_length => shift,
|
||||
_arrayElementBits => shift
|
||||
};
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
@ -283,18 +292,18 @@ sub addValue
|
||||
|
||||
sub getValue
|
||||
{
|
||||
my ($self, $byteArrayRef) = @_;
|
||||
my ($self, $byteArrayRef, $index) = @_;
|
||||
|
||||
my $value = SHC_util::getUInt($byteArrayRef, $self->{_offset}, $self->{_bits});
|
||||
my $value = SHC_util::getUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits});
|
||||
return $value2name{$value};
|
||||
}
|
||||
|
||||
sub setValue
|
||||
{
|
||||
my ($self, $byteArrayRef, $name) = @_;
|
||||
my ($self, $byteArrayRef, $name, $index) = @_;
|
||||
|
||||
my $value = $name2value{$name};
|
||||
SHC_util::setUInt($byteArrayRef, $self->{_offset}, $self->{_bits}, $value);
|
||||
SHC_util::setUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits}, $value);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -34,7 +34,7 @@
|
||||
# $parser->parse("Packet Data: SenderID=22;...");
|
||||
# 3.) Get MessageGroupName: my $grp = $parser->getMessageGroupName();
|
||||
# 4.) Get MessageName: my $msg = $parser->getMessageName();
|
||||
# 5.) Get data fields depending on MessageGroupname and MessageName, e.g.
|
||||
# 5.) Get data fields depending on MessageGroupName and MessageName, e.g.
|
||||
# $val = $parser->getField("Temperature");
|
||||
#
|
||||
# Sending packets:
|
||||
@ -74,6 +74,8 @@ my %messageID2bits = ();
|
||||
my @msgData = ();
|
||||
my $sendMode = 0;
|
||||
|
||||
my $offset = 0;
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
@ -92,6 +94,104 @@ sub new
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub init_datafield_positions_noarray($$$$$)
|
||||
{
|
||||
my ($messageGroupID, $messageID, $field, $arrayLength, $arrayElementBits) = @_;
|
||||
|
||||
given ($field->nodeName) {
|
||||
when ('UIntValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = ($field->findnodes("Bits"))[0]->textContent;
|
||||
|
||||
# print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} =
|
||||
new UIntValue($id, $offset, $bits, $arrayLength, $arrayElementBits);
|
||||
|
||||
$offset += $bits;
|
||||
}
|
||||
|
||||
when ('IntValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = ($field->findnodes("Bits"))[0]->textContent;
|
||||
|
||||
# print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} =
|
||||
new IntValue($id, $offset, $bits, $arrayLength, $arrayElementBits);
|
||||
|
||||
$offset += $bits;
|
||||
}
|
||||
|
||||
when ('BoolValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = 1;
|
||||
|
||||
# print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} =
|
||||
new BoolValue($id, $offset, $arrayLength, $arrayElementBits);
|
||||
|
||||
$offset += $bits;
|
||||
}
|
||||
|
||||
when ('EnumValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = ($field->findnodes("Bits"))[0]->textContent;
|
||||
|
||||
# print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
my $object = new EnumValue($id, $offset, $bits, $arrayLength, $arrayElementBits);
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} = $object;
|
||||
|
||||
for my $element ($field->findnodes("Element")) {
|
||||
my $value = ($element->findnodes("Value"))[0]->textContent;
|
||||
my $name = ($element->findnodes("Name"))[0]->textContent;
|
||||
|
||||
$object->addValue($name, $value);
|
||||
}
|
||||
|
||||
$offset += $bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub init_datafield_positions_array($$$)
|
||||
{
|
||||
my ($messageGroupID, $messageID, $field) = @_;
|
||||
my $offsetStartArray = $offset;
|
||||
|
||||
my $arrayLength = int(($field->findnodes("Length"))[0]->textContent);
|
||||
|
||||
my $arrayElementBits =
|
||||
calc_array_bits_ovr($field); # number of bits for one struct ("set of sub-elements") in a structured array
|
||||
# print "Next field is an array with " . $arrayLength . " elements (" . $arrayElementBits . " ovr bits per array element)!\n";
|
||||
|
||||
for my $subfield ($field->findnodes("UIntValue|IntValue|BoolValue|EnumValue")) {
|
||||
my $bits =
|
||||
init_datafield_positions_noarray($messageGroupID, $messageID, $subfield, $arrayLength, $arrayElementBits);
|
||||
}
|
||||
|
||||
$offset = $offsetStartArray + $arrayLength * $arrayElementBits;
|
||||
}
|
||||
|
||||
# Calculate the overall bits for one struct in a structured array
|
||||
sub calc_array_bits_ovr($)
|
||||
{
|
||||
my ($field) = @_;
|
||||
my $bits = 0;
|
||||
|
||||
for my $subfield ($field->findnodes("BoolValue")) {
|
||||
$bits += 1;
|
||||
}
|
||||
|
||||
for my $subfield ($field->findnodes("UIntValue|IntValue|EnumValue")) {
|
||||
$bits += ($subfield->findnodes("Bits"))[0]->textContent;
|
||||
}
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
# Read packet layout from XML file and remember the defined MessageGroups,
|
||||
# Messages and data fields (incl. positions, length).
|
||||
sub init_datafield_positions()
|
||||
@ -121,75 +221,21 @@ sub init_datafield_positions()
|
||||
$messageID2messageName{$messageGroupID . "-" . $messageID} = $messageName;
|
||||
$messageName2messageID{$messageGroupName . "-" . $messageName} = $messageID;
|
||||
|
||||
my $offset = 0;
|
||||
my $arrayLength = 1;
|
||||
$offset = 0;
|
||||
|
||||
for my $field ($message->findnodes("Array|UIntValue|IntValue|BoolValue|EnumValue")) {
|
||||
|
||||
# When an array is detected, remember the array length and change the current field node
|
||||
# to the inner node for further processing.
|
||||
if ($field->nodeName eq 'Array') {
|
||||
$arrayLength = int(($field->findnodes("Length"))[0]->textContent);
|
||||
# DEBUG print "Next field is an array with " . $arrayLength . " elements!\n";
|
||||
|
||||
$field = ($field->findnodes("UIntValue|IntValue|BoolValue|EnumValue"))[0];
|
||||
}
|
||||
|
||||
given ($field->nodeName) {
|
||||
when ('UIntValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = ($field->findnodes("Bits"))[0]->textContent;
|
||||
|
||||
# DEBUG print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} = new UIntValue($id, $offset, $bits);
|
||||
|
||||
$offset += $bits * $arrayLength;
|
||||
}
|
||||
|
||||
when ('IntValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = ($field->findnodes("Bits"))[0]->textContent;
|
||||
|
||||
# DEBUG print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} = new IntValue($id, $offset, $bits);
|
||||
|
||||
$offset += $bits * $arrayLength;
|
||||
}
|
||||
|
||||
when ('BoolValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = 1;
|
||||
|
||||
# DEBUG print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} = new BoolValue($id, $offset, $arrayLength);
|
||||
|
||||
$offset += $bits * $arrayLength;
|
||||
}
|
||||
|
||||
when ('EnumValue') {
|
||||
my $id = ($field->findnodes("ID"))[0]->textContent;
|
||||
my $bits = ($field->findnodes("Bits"))[0]->textContent;
|
||||
|
||||
# DEBUG print "Data field " . $id . " starts at " . $offset . " with " . $bits . " bits.\n";
|
||||
|
||||
my $object = new EnumValue($id, $offset, $bits);
|
||||
$dataFields{$messageGroupID . "-" . $messageID . "-" . $id} = $object;
|
||||
|
||||
for my $element ($field->findnodes("Element")) {
|
||||
my $value = ($element->findnodes("Value"))[0]->textContent;
|
||||
my $name = ($element->findnodes("Name"))[0]->textContent;
|
||||
|
||||
$object->addValue($name, $value);
|
||||
}
|
||||
|
||||
$offset += $bits * $arrayLength;
|
||||
}
|
||||
init_datafield_positions_array($messageGroupID, $messageID, $field);
|
||||
} else {
|
||||
init_datafield_positions_noarray($messageGroupID, $messageID, $field, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
# DEBUG print "Remember packet length " . $offset . " bits for MessageGroupID " . $messageGroupID . ", MessageID " . $messageID . "\n";
|
||||
|
||||
$messageID2bits{$messageGroupID . "-" . $messageID} = $offset;
|
||||
}
|
||||
}
|
||||
@ -275,8 +321,14 @@ sub getField
|
||||
{
|
||||
my ($self, $fieldName, $index) = @_;
|
||||
|
||||
if (!defined $index) {
|
||||
$index = 0;
|
||||
}
|
||||
|
||||
my $obj = $dataFields{$self->{_messageGroupID} . "-" . $self->{_messageID} . "-" . $fieldName};
|
||||
my @tmpArray = map hex("0x$_"), $self->{_messageData} =~ /(..)/g;
|
||||
|
||||
# add 256 "empty" bytes to have enough data in the array because the message may be truncated
|
||||
my @tmpArray = map hex("0x$_"), ($self->{_messageData} . ("00" x 256)) =~ /(..)/g;
|
||||
|
||||
return $obj->getValue(\@tmpArray, $index);
|
||||
}
|
||||
@ -290,23 +342,27 @@ sub initPacket
|
||||
$self->{_messageGroupID} = $messageGroupName2messageGroupID{$messageGroupName};
|
||||
$self->{_messageID} = $messageName2messageID{$messageGroupName . "-" . $messageName};
|
||||
|
||||
my $lenBytes = $messageID2bits{$self->{_messageGroupID} . "-" . $self->{_messageID}} / 8;
|
||||
my $lenBytes = int(($messageID2bits{$self->{_messageGroupID} . "-" . $self->{_messageID}} + 7) / 8);
|
||||
|
||||
@msgData = 0 x $lenBytes;
|
||||
@msgData = (0) x $lenBytes;
|
||||
|
||||
$sendMode = 1;
|
||||
}
|
||||
|
||||
sub setField
|
||||
{
|
||||
my ($self, $messageGroupName, $messageName, $fieldName, $value) = @_;
|
||||
my ($self, $messageGroupName, $messageName, $fieldName, $value, $index) = @_;
|
||||
|
||||
if (!defined $index) {
|
||||
$index = 0;
|
||||
}
|
||||
|
||||
my $gID = $messageGroupName2messageGroupID{$messageGroupName};
|
||||
my $mID = $messageName2messageID{$messageGroupName . "-" . $messageName};
|
||||
|
||||
my $obj = $dataFields{$gID . "-" . $mID . "-" . $fieldName};
|
||||
|
||||
$obj->setValue(\@msgData, $value);
|
||||
$obj->setValue(\@msgData, $value, $index);
|
||||
}
|
||||
|
||||
# sKK01RRRRGGMMDD
|
||||
@ -322,6 +378,10 @@ sub getSendString
|
||||
# Add lookup table device -> AES key?
|
||||
# Automatically gather used AES key after reception from device?
|
||||
|
||||
if (!defined $aesKeyNr) {
|
||||
$aesKeyNr = 0;
|
||||
}
|
||||
|
||||
my $s = "s"
|
||||
. sprintf("%02X", $aesKeyNr)
|
||||
. sprintf("%02X", $self->{_messageTypeID})
|
||||
|
@ -260,6 +260,35 @@
|
||||
</BoolValue>
|
||||
</Array>
|
||||
</Message>
|
||||
<Message>
|
||||
<Name>AnalogPin</Name>
|
||||
<Description>This is the voltage of up to 8 ADC channels. The ATMega328 in the PDIP package has only 6 ADCs and one ADC may be blocked by the battery voltage measurement, so there may be less than 8 ADC values reported depending on the device and configuration.</Description>
|
||||
<MessageID>2</MessageID>
|
||||
<MessageType>0</MessageType>
|
||||
<MessageType>1</MessageType>
|
||||
<MessageType>2</MessageType>
|
||||
<MessageType>8</MessageType>
|
||||
<MessageType>9</MessageType>
|
||||
<MessageType>10</MessageType>
|
||||
<Validity>test</Validity>
|
||||
<Array>
|
||||
<Length>8</Length>
|
||||
<BoolValue>
|
||||
<ID>On</ID>
|
||||
<Description>Tells if the pin is on (voltage over trigger threshold) or not.</Description>
|
||||
</BoolValue>
|
||||
</Array>
|
||||
<Array>
|
||||
<Length>8</Length>
|
||||
<UIntValue>
|
||||
<ID>Voltage</ID>
|
||||
<Description>This is the voltage level in mV.</Description>
|
||||
<Bits>11</Bits>
|
||||
<MinVal>0</MinVal>
|
||||
<MaxVal>1100</MaxVal>
|
||||
</UIntValue>
|
||||
</Array>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Name>Weather</Name>
|
||||
@ -491,5 +520,64 @@
|
||||
<MaxVal>100</MaxVal>
|
||||
</UIntValue>
|
||||
</Message>
|
||||
<Message>
|
||||
<Name>Color</Name>
|
||||
<Description>This is to set a fixed color.</Description>
|
||||
<MessageID>10</MessageID>
|
||||
<MessageType>0</MessageType>
|
||||
<MessageType>1</MessageType>
|
||||
<MessageType>2</MessageType>
|
||||
<MessageType>8</MessageType>
|
||||
<MessageType>9</MessageType>
|
||||
<MessageType>10</MessageType>
|
||||
<Validity>test</Validity>
|
||||
<UIntValue>
|
||||
<ID>Color</ID>
|
||||
<Description>The color is according to the 6 bit color palette used in SHC.</Description>
|
||||
<Bits>6</Bits>
|
||||
<MinVal>0</MinVal>
|
||||
<MaxVal>63</MaxVal>
|
||||
</UIntValue>
|
||||
</Message>
|
||||
<Message>
|
||||
<Name>ColorAnimation</Name>
|
||||
<Description>This is to set a color animation.</Description>
|
||||
<MessageID>11</MessageID>
|
||||
<MessageType>0</MessageType>
|
||||
<MessageType>1</MessageType>
|
||||
<MessageType>2</MessageType>
|
||||
<MessageType>8</MessageType>
|
||||
<MessageType>9</MessageType>
|
||||
<MessageType>10</MessageType>
|
||||
<Validity>test</Validity>
|
||||
<UIntValue>
|
||||
<ID>Repeat</ID>
|
||||
<Description>The number of times the animation will be repeated. 0 means infinitely.</Description>
|
||||
<Bits>4</Bits>
|
||||
<MinVal>0</MinVal>
|
||||
<MaxVal>15</MaxVal>
|
||||
</UIntValue>
|
||||
<BoolValue>
|
||||
<ID>AutoReverse</ID>
|
||||
<Description>If true, the animation will be played back in the normal direction and then in reverse order.</Description>
|
||||
</BoolValue>
|
||||
<Array>
|
||||
<Length>10</Length>
|
||||
<UIntValue>
|
||||
<ID>Time</ID>
|
||||
<Description>The time for the animation between the current color and the next one. The number of seconds used is 0.05 * 1.3 ^ Time and covers the range from 0.03s to 170s. Use 0 to mark the end of the animation. Further values will be ignored.</Description>
|
||||
<Bits>5</Bits>
|
||||
<MinVal>0</MinVal>
|
||||
<MaxVal>31</MaxVal>
|
||||
</UIntValue>
|
||||
<UIntValue>
|
||||
<ID>Color</ID>
|
||||
<Description>The color is according to the 6 bit color palette used in SHC. The last color (or the first when AutoReverse is true) of the animation will remain visible after the animation is completed.</Description>
|
||||
<Bits>6</Bits>
|
||||
<MinVal>0</MinVal>
|
||||
<MaxVal>63</MaxVal>
|
||||
</UIntValue>
|
||||
</Array>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
</Packet>
|
||||
|
@ -260,8 +260,11 @@ FHEM/HttpUtils.pm rudolfkoenig http://forum.fhem.de Automatis
|
||||
FHEM/MaxCommon.pm mgehre http://forum.fhem.de MAX
|
||||
FHEM/ONKYOdb.pm loredo http://forum.fhem.de Multimedia
|
||||
FHEM/SetExtensions.pm rudolfkoenig http://forum.fhem.de Automatisierung
|
||||
FHEM/SHC_datafields.pm rr2000 http://forum.fhem.de Sonstige Systeme
|
||||
FHEM/SHC_parser.pm rr2000 http://forum.fhem.de Sonstige Systeme
|
||||
FHEM/TcpServerUtils.pm rudolfkoenig http://forum.fhem.de Automatisierung
|
||||
FHEM/lib/Device/Firmata/* ntruchsess http://forum.fhem.de Sonstiges
|
||||
FHEM/lib/SHC_packet_layout.xml rr2000 http://forum.fhem.de Sonstige Systeme
|
||||
FHEM/lib/SWAP/* justme1968 http://forum.fhem.de Sonstige Systeme
|
||||
FHEM/FhemUtils/* mfr69bs http://forum.fhem.de Sonstiges
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user