37_SHC: now add all files for the previous commit (rr2000)

git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@8182 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rr2000 2015-03-09 19:03:15 +00:00
parent 693e2d4fd9
commit 4688bb5055
6 changed files with 405 additions and 130 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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. # Do not insert empty lines here, update check depends on it.
- changed: 37_SHC: now add all files for the previous commit (rr2000)
- feature: 37_SHC: add new support for SoilMoistureMeter and add - feature: 37_SHC: add new support for SoilMoistureMeter and add
support for DigPort and DigPin in Powerswitch (rr2000) support for DigPort and DigPin in Powerswitch (rr2000)
- feature: 02_HTTPSRV: query string sets readings (Stefan Strobel) - feature: 02_HTTPSRV: query string sets readings (Stefan Strobel)

View File

@ -2,6 +2,7 @@
# This file is part of the smarthomatic module for FHEM. # This file is part of the smarthomatic module for FHEM.
# #
# Copyright (c) 2014 Stefan Baumann # Copyright (c) 2014 Stefan Baumann
# 2015 Uwe Freese
# #
# You can find smarthomatic at www.smarthomatic.org. # You can find smarthomatic at www.smarthomatic.org.
# You can find FHEM at www.fhem.de. # You can find FHEM at www.fhem.de.
@ -26,6 +27,7 @@ package main;
use strict; use strict;
use warnings; use warnings;
use Time::HiRes qw(gettimeofday); use Time::HiRes qw(gettimeofday);
use Digest::CRC qw(crc32); # linux packet libdigest-crc-perl
sub SHC_Parse($$$$); sub SHC_Parse($$$$);
sub SHC_Read($); sub SHC_Read($);
@ -37,7 +39,7 @@ sub SHC_SimpleWrite(@);
my $clientsSHC = ":SHCdev:BASE:xxx:"; my $clientsSHC = ":SHCdev:BASE:xxx:";
my %matchListSHC = ( my %matchListSHC = (
"1:SHCdev" => "^Packet Data: SenderID=[1-9]|0[1-9]|[1-9][0-9]|[0-9][0-9][0-9]|[0-3][0-9][0-9][0-9]|40[0-8][0-9]|409[0-6]", #1-4096 with leading zeros "1:SHCdev" => "^PKT:SID=([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-3][0-9][0-9][0-9]|40[0-8][0-9]|409[0-6]);", #1-4096
"2:xxx" => "^\\S+\\s+22", "2:xxx" => "^\\S+\\s+22",
"3:xxx" => "^\\S+\\s+11", "3:xxx" => "^\\S+\\s+11",
"4:xxx" => "^\\S+\\s+9 ", "4:xxx" => "^\\S+\\s+9 ",
@ -269,11 +271,15 @@ sub SHC_Parse($$$$)
next if (!$dmsg || length($dmsg) < 1); # Bogus messages next if (!$dmsg || length($dmsg) < 1); # Bogus messages
if ($dmsg !~ m/^Packet Data: SenderID=/) { if ($dmsg =~ m/^PKT:SID=0;/) { # "echo" from message sent by FHEM itself
return;
}
if ($dmsg !~ m/^PKT:SID=/) {
# Messages just to dipose # Messages just to dipose
if ( $dmsg =~ m/^\*\*\* Enter AES key nr/ if ( $dmsg =~ m/^\*\*\* Enter data/
|| $dmsg =~ m/^\*\*\* Received character/) || $dmsg =~ m/^\*\*\* 0x/)
{ {
return; return;
} }
@ -294,17 +300,34 @@ sub SHC_Parse($$$$)
# -Verbosity level 4 # -Verbosity level 4
if ( $dmsg =~ m/^Request added to queue/ if ( $dmsg =~ m/^Request added to queue/
|| $dmsg =~ m/^Request Buffer/ || $dmsg =~ m/^Request Buffer/
|| $dmsg =~ m/^Request (q|Q)ueue/) || $dmsg =~ m/^Request Queue/)
{ {
Log3 $name, 4, "$name: $dmsg"; Log3 $name, 4, "$name: $dmsg";
return; return;
} }
# -Verbosity level 1
if ( $dmsg =~ m/^CRC Error/ )
{
Log3 $name, 1, "$name: $dmsg";
return;
}
# Anything else in verbosity level 3 # Anything else in verbosity level 3
Log3 $name, 3, "$name: $dmsg"; Log3 $name, 3, "$name: $dmsg";
return; return;
} }
# check CRC of "PKT:..." message and ignore message if necessary
my $crc = crc32(substr($dmsg, 4, length($dmsg) - 12));
$crc = sprintf("%08x", $crc);
if ($crc ne substr($dmsg, length($dmsg) - 8))
{
Log3 $name, 1, "$name: CRC Error (" . $crc . ") $dmsg";
return;
}
$hash->{"${name}_MSGCNT"}++; $hash->{"${name}_MSGCNT"}++;
$hash->{"${name}_TIME"} = TimeNow(); $hash->{"${name}_TIME"} = TimeNow();
$hash->{RAWMSG} = $rmsg; $hash->{RAWMSG} = $rmsg;

View File

@ -1,7 +1,8 @@
########################################################################## ##########################################################################
# This file is part of the smarthomatic module for FHEM. # This file is part of the smarthomatic module for FHEM.
# #
# Copyright (c) 2014 Stefan Baumann, Uwe Freese # Copyright (c) 2014 Stefan Baumann
# 2014..2015 Uwe Freese
# #
# You can find smarthomatic at www.smarthomatic.org. # You can find smarthomatic at www.smarthomatic.org.
# You can find FHEM at www.fhem.de. # You can find FHEM at www.fhem.de.
@ -33,37 +34,41 @@ use SHC_parser;
my $parser = new SHC_parser(); my $parser = new SHC_parser();
my %dev_state_icons = ( my %dev_state_icons = (
"PowerSwitch" => "on:on:toggle off:off:toggle set.*:light_question:off", "PowerSwitch" => ".*1\\d{7}:on:off .*0\\d{7}:off:on set.*:light_question:off",
"Dimmer" => "on:on off:off set.*:light_question:off", "Dimmer" => "on:on off:off set.*:light_question:off",
"EnvSensor" => undef, "EnvSensor" => undef,
"RGB_Dimmer" => undef "RGBDimmer" => undef,
"SoilMoistureMeter" => ".*H:\\s\\d\\..*:ampel_rot"
); );
my %web_cmds = ( my %web_cmds = (
"PowerSwitch" => "on:off:toggle:statusRequest", "PowerSwitch" => "on:off:toggle:statusRequest",
"Dimmer" => "on:off:statusRequest", "Dimmer" => "on:off:statusRequest",
"EnvSensor" => undef, "EnvSensor" => undef,
"RGB_Dimmer" => undef "RGBDimmer" => undef,
"SoilMoistureMeter" => undef
); );
# Array format: [ reading1, str_format1, reading2, str_format2 ... ] # Array format: [ reading1, str_format1, reading2, str_format2 ... ]
# "on" reading translates 0 -> "off" # "on" reading translates 0 -> "off"
# 1 -> "on" # 1 -> "on"
my %dev_state_format = ( my %dev_state_format = (
"PowerSwitch" => ["on", ""], "PowerSwitch" => ["port", "Port: "],
"Dimmer" => ["on", "", "brightness", "B: "], "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: ", "temperature", "T: ",
"humidity", "H: ", "humidity", "H: ",
"barometric_pressure", "Baro: ", "barometric_pressure", "Baro: ",
"brightness", "B: ", "brightness", "B: ",
"distance", "D: ", "distance", "D: ",
"dins", "Din: ", "port", "Port: ",
"ains", "Ain: " "ains", "Ain: "
], ],
"RGB_Dimmer" => [ "RGBDimmer" => [
"color", "Color: " "color", "Color: ",
] "brightness", "Brightness: "
],
"SoilMoistureMeter" => ["humidity", "H: "]
); );
# Supported set commands # Supported set commands
@ -71,19 +76,23 @@ my %dev_state_format = (
# use "cmd_name:cmd_additional_info" # use "cmd_name:cmd_additional_info"
# cmd_additional_info: Description available at http://www.fhemwiki.de/wiki/DevelopmentModuleIntro#X_Set # cmd_additional_info: Description available at http://www.fhemwiki.de/wiki/DevelopmentModuleIntro#X_Set
my %sets = ( my %sets = (
"PowerSwitch" => "on:noArg off:noArg toggle:noArg statusRequest:noArg " . "PowerSwitch" => "on:noArg off:noArg toggle:noArg statusRequest:noArg " .
# Used from SetExtensions.pm # Used from SetExtensions.pm
"blink on-for-timer on-till off-for-timer off-till intervals", "blink on-for-timer on-till off-for-timer off-till intervals " .
"Dimmer" => "on:noArg off:noArg toggle:noArg statusRequest:noArg pct:slider,0,1,100 ani " . "DigitalPort " .
# Used from SetExtensions.pm "DigitalPortTimeout " .
"blink on-for-timer on-till off-for-timer off-till intervals", "DigitalPin " .
"EnvSensor" => "", "DigitalPinTimeout",
"RGB_Dimmer" => "Color " . "Dimmer" => "on:noArg off:noArg toggle:noArg statusRequest:noArg pct:slider,0,1,100 ani " .
"ColorAnimation", # Used from SetExtensions.pm
"Custom" => "PowerSwitch.SwitchState " . "blink on-for-timer on-till off-for-timer off-till intervals",
"PowerSwitch.SwitchStateExt " . "EnvSensor" => "",
"Dimmer.Brightness " . "RGBDimmer" => "Color " .
"Dimmer.Animation" "ColorAnimation " .
"Dimmer.Brightness:slider,0,1,100",
"SoilMoistureMeter" => "",
"Custom" => "Dimmer.Brightness " .
"Dimmer.Animation"
); );
# Supported get commands # Supported get commands
@ -92,27 +101,10 @@ my %gets = (
"PowerSwitch" => "", "PowerSwitch" => "",
"Dimmer" => "", "Dimmer" => "",
"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", "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" => "", "RGBDimmer" => "",
"Custom" => "" "Custom" => ""
); );
# Hashtable for automatic device type assignment
# Format:
# "MessageGroupName:MessageName" => "Auto Device Type"
my %auto_devtype = (
"Weather.Temperature" => "EnvSensor",
"Weather.HumidityTemperature" => "EnvSensor",
"Weather.BarometricPressureTemperature" => "EnvSensor",
"Environment.Brightness" => "EnvSensor",
"Environment.Distance" => "EnvSensor",
"GPIO.DigitalPin" => "EnvSensor",
"GPIO.AnalogPin" => "EnvSensor",
"PowerSwitch.SwitchState" => "PowerSwitch",
"Dimmer.Brightness" => "Dimmer",
"Dimmer.Color" => "RGB_Dimmer",
"Dimmer.ColorAnimation" => "RGB_Dimmer"
);
sub SHCdev_Parse($$); sub SHCdev_Parse($$);
##################################### #####################################
@ -120,7 +112,7 @@ sub SHCdev_Initialize($)
{ {
my ($hash) = @_; my ($hash) = @_;
$hash->{Match} = "^Packet Data: SenderID=[1-9]|0[1-9]|[1-9][0-9]|[0-9][0-9][0-9]|[0-3][0-9][0-9][0-9]|40[0-8][0-9]|409[0-6]"; $hash->{Match} = "^PKT:SID=([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-3][0-9][0-9][0-9]|40[0-8][0-9]|409[0-6]);";
$hash->{SetFn} = "SHCdev_Set"; $hash->{SetFn} = "SHCdev_Set";
$hash->{GetFn} = "SHCdev_Get"; $hash->{GetFn} = "SHCdev_Get";
$hash->{DefFn} = "SHCdev_Define"; $hash->{DefFn} = "SHCdev_Define";
@ -130,7 +122,7 @@ sub SHCdev_Initialize($)
." readonly:1" ." readonly:1"
." forceOn:1" ." forceOn:1"
." $readingFnAttributes" ." $readingFnAttributes"
." devtype:EnvSensor,Dimmer,PowerSwitch,RGB_Dimmer"; ." devtype:EnvSensor,Dimmer,PowerSwitch,RGBDimmer,SoilMoistureMeter";
} }
##################################### #####################################
@ -198,7 +190,7 @@ sub SHCdev_Parse($$)
my $name = $hash->{NAME}; my $name = $hash->{NAME};
if (!$parser->parse($msg)) { if (!$parser->parse($msg)) {
Log3 $hash, 4, "SHC_TEMP: parser error: $msg"; Log3 $name, 1, "$name: Parser error: $msg";
return ""; return "";
} }
@ -210,7 +202,7 @@ sub SHCdev_Parse($$)
my $rname = $rhash ? $rhash->{NAME} : $raddr; my $rname = $rhash ? $rhash->{NAME} : $raddr;
if (!$modules{SHCdev}{defptr}{$raddr}) { if (!$modules{SHCdev}{defptr}{$raddr}) {
Log3 $name, 3, "SHC_TEMP: Unknown device $rname, please define it"; Log3 $name, 3, "$name: Unknown device $rname, please define it";
return "UNDEFINED SHCdev_$rname SHCdev $raddr"; return "UNDEFINED SHCdev_$rname SHCdev $raddr";
} }
@ -234,9 +226,6 @@ sub SHCdev_Parse($$)
given ($msggroupname) { given ($msggroupname) {
when ('Generic') { when ('Generic') {
given ($msgname) { given ($msgname) {
when ('BatteryStatus') {
readingsBulkUpdate($rhash, "battery", $parser->getField("Percentage"));
}
when ('Version') { when ('Version') {
my $major = $parser->getField("Major"); my $major = $parser->getField("Major");
my $minor = $parser->getField("Minor"); my $minor = $parser->getField("Minor");
@ -244,22 +233,61 @@ sub SHCdev_Parse($$)
my $vhash = $parser->getField("Hash"); my $vhash = $parser->getField("Hash");
readingsBulkUpdate($rhash, "version", "$major.$minor.$patch-$vhash"); readingsBulkUpdate($rhash, "version", "$major.$minor.$patch-$vhash");
}
when ('DeviceInfo') {
my $devtype = $parser->getField("DeviceType");
my $major = $parser->getField("VersionMajor");
my $minor = $parser->getField("VersionMinor");
my $patch = $parser->getField("VersionPatch");
my $vhash = $parser->getField("VersionHash");
# Assign device type
my $devtypeOld = AttrVal( $rname, "devtype", undef );
if (!defined($devtypeOld)) {
$attr{$rname}{devtype} = $devtype;
Log3 $name, 3, "$rname: Assign device type = " . $attr{$rname}{devtype};
}
readingsBulkUpdate($rhash, "version", "$major.$minor.$patch-$vhash");
}
when ('BatteryStatus') {
readingsBulkUpdate($rhash, "battery", $parser->getField("Percentage"));
} }
} }
} }
when ('GPIO') { when ('GPIO') {
given ($msgname) { given ($msgname) {
when ('DigitalPin') { when ('DigitalPortTimeout') {
my $pins = "";
for (my $i = 0 ; $i < 8 ; $i++) {
my $pinx = $parser->getField("On", $i);
my $timeoutx = $parser->getField("TimeoutSec", $i);
my $channel = $i + 1;
if ($channel == 1)
{
readingsBulkUpdate($rhash, "on", $pinx);
}
readingsBulkUpdate($rhash, "pin" . $channel, $pinx);
readingsBulkUpdate($rhash, "timeout" . $channel, $timeoutx);
$pins .= $pinx;
}
readingsBulkUpdate($rhash, "port", $pins);
}
when ('DigitalPort') {
my $pins = ""; my $pins = "";
for (my $i = 0 ; $i < 8 ; $i++) { for (my $i = 0 ; $i < 8 ; $i++) {
my $pinx = $parser->getField("On", $i); my $pinx = $parser->getField("On", $i);
my $channel = $i + 1; my $channel = $i + 1;
readingsBulkUpdate($rhash, "din" . $channel, $pinx); if ($channel == 1)
{
readingsBulkUpdate($rhash, "on", $pinx);
}
readingsBulkUpdate($rhash, "pin" . $channel, $pinx);
$pins .= $pinx; $pins .= $pinx;
} }
readingsBulkUpdate($rhash, "dins", $pins); readingsBulkUpdate($rhash, "port", $pins);
} }
when ('AnalogPin') { when ('AnalogPort') {
my $pins = ""; my $pins = "";
for (my $i = 0 ; $i < 5 ; $i++) { for (my $i = 0 ; $i < 5 ; $i++) {
my $pinx_on = $parser->getField("On", $i); my $pinx_on = $parser->getField("On", $i);
@ -294,6 +322,11 @@ sub SHCdev_Parse($$)
readingsBulkUpdate($rhash, "barometric_pressure", $bar); readingsBulkUpdate($rhash, "barometric_pressure", $bar);
readingsBulkUpdate($rhash, "temperature", $tmp); readingsBulkUpdate($rhash, "temperature", $tmp);
} }
when ('Humidity') {
my $hum = $parser->getField("Humidity") / 10; # parser returns 1/10 percent
readingsBulkUpdate($rhash, "humidity", $hum);
}
} }
} }
when ('Environment') { when ('Environment') {
@ -308,17 +341,6 @@ sub SHCdev_Parse($$)
} }
} }
} }
when ('PowerSwitch') {
given ($msgname) {
when ('SwitchState') {
my $on = $parser->getField("On");
my $timeout = $parser->getField("TimeoutSec");
readingsBulkUpdate($rhash, "on", $on);
readingsBulkUpdate($rhash, "timeout", $timeout);
}
}
}
when ('Dimmer') { when ('Dimmer') {
given ($msgname) { given ($msgname) {
when ('Brightness') { when ('Brightness') {
@ -348,13 +370,6 @@ sub SHCdev_Parse($$)
} }
} }
# Autoassign device type
my $devtype = AttrVal( $rname, "devtype", undef );
if (!defined($devtype) && (defined($auto_devtype{"$msggroupname.$msgname"}))) {
$attr{$rname}{devtype} = $auto_devtype{"$msggroupname.$msgname"};
Log3 $name, 3, "$rname: Autoassign device type = " . $attr{$rname}{devtype};
}
# If the devtype is defined add, if not already done, the according webCmds and devStateIcons # If the devtype is defined add, if not already done, the according webCmds and devStateIcons
my $devtype2 = AttrVal( $rname, "devtype", undef ); my $devtype2 = AttrVal( $rname, "devtype", undef );
if (defined($devtype2)) { if (defined($devtype2)) {
@ -446,23 +461,56 @@ sub SHCdev_Set($@)
# is able to do this as well. Even more it supports intervals, off-for-timer, off-till ... # is able to do this as well. Even more it supports intervals, off-for-timer, off-till ...
if ($cmd eq 'toggle') { if ($cmd eq 'toggle') {
$cmd = ReadingsVal($name, "state", "on") eq "off" ? "on" : "off"; $cmd = ReadingsVal($name, "on", "0") eq "0" ? "on" : "off";
} }
if (!$readonly && $cmd eq 'off') { if (!$readonly && $cmd eq 'off') {
readingsSingleUpdate($hash, "state", "set-$cmd", 1); readingsSingleUpdate($hash, "state", "set-$cmd", 1);
$parser->initPacket("PowerSwitch", "SwitchState", "SetGet"); $parser->initPacket("GPIO", "DigitalPin", "SetGet");
$parser->setField("PowerSwitch", "SwitchState", "TimeoutSec", 0); $parser->setField("GPIO", "DigitalPin", "Pos", 0);
$parser->setField("PowerSwitch", "SwitchState", "On", 0); $parser->setField("GPIO", "DigitalPin", "On", 0);
SHCdev_Send($hash); SHCdev_Send($hash);
} elsif (!$readonly && $cmd eq 'on') { } elsif (!$readonly && $cmd eq 'on') {
readingsSingleUpdate($hash, "state", "set-$cmd", 1); readingsSingleUpdate($hash, "state", "set-$cmd", 1);
$parser->initPacket("PowerSwitch", "SwitchState", "SetGet"); $parser->initPacket("GPIO", "DigitalPin", "SetGet");
$parser->setField("PowerSwitch", "SwitchState", "TimeoutSec", 0); $parser->setField("GPIO", "DigitalPin", "Pos", 0);
$parser->setField("PowerSwitch", "SwitchState", "On", 1); $parser->setField("GPIO", "DigitalPin", "On", 1);
SHCdev_Send($hash); SHCdev_Send($hash);
} elsif ($cmd eq 'statusRequest') { } elsif ($cmd eq 'statusRequest') {
$parser->initPacket("PowerSwitch", "SwitchState", "Get"); $parser->initPacket("GPIO", "DigitalPin", "Get");
SHCdev_Send($hash);
} elsif ($cmd eq 'DigitalPort') {
$parser->initPacket("GPIO", "DigitalPort", "SetGet");
# if not enough (less than 8) pinbits are available use zero as default
my $pinbits = $arg . "00000000";
for (my $i = 0 ; $i < 8 ; $i = $i + 1) {
$parser->setField("GPIO", "DigitalPort", "On", substr($pinbits, $i , 1), $i);
}
SHCdev_Send($hash);
} elsif ($cmd eq 'DigitalPortTimeout') { # TODO implement correctly
$parser->initPacket("GPIO", "DigitalPortTimeout", "SetGet");
# if not enough (less than 8) pinbits are available use zero as default
my $pinbits = $arg . "00000000";
for (my $i = 0 ; $i < 8 ; $i = $i + 1) {
my $pintimeout = "0"; # default value for timeout
if (exists $aa[$i + 2]) {
$pintimeout = $aa[$i + 2];
}
Log3 $name, 3, "$name: $i: Pin: " . substr($pinbits, $i , 1) . " Timeout: $pintimeout";
$parser->setField("GPIO", "DigitalPortTimeout", "On", substr($pinbits, $i , 1), $i);
$parser->setField("GPIO", "DigitalPortTimeout", "TimeoutSec", $pintimeout, $i);
}
SHCdev_Send($hash);
} elsif ($cmd eq 'DigitalPin') {
$parser->initPacket("GPIO", "DigitalPin", "SetGet");
$parser->setField("GPIO", "DigitalPin", "Pos", $arg);
$parser->setField("GPIO", "DigitalPin", "On", $arg2);
SHCdev_Send($hash);
} elsif ($cmd eq 'DigitalPinTimeout') {
$parser->initPacket("GPIO", "DigitalPinTimeout", "SetGet");
$parser->setField("GPIO", "DigitalPinTimeout", "Pos", $arg);
$parser->setField("GPIO", "DigitalPinTimeout", "On", $arg2);
$parser->setField("GPIO", "DigitalPinTimeout", "TimeoutSec", $arg3);
SHCdev_Send($hash); SHCdev_Send($hash);
} else { } else {
return SetExtensions($hash, "", $name, @aa); return SetExtensions($hash, "", $name, @aa);
@ -519,7 +567,7 @@ sub SHCdev_Set($@)
return SetExtensions($hash, "", $name, @aa); return SetExtensions($hash, "", $name, @aa);
} }
} }
when ('RGB_Dimmer') { when ('RGBDimmer') {
if ($cmd eq 'Color') { if ($cmd eq 'Color') {
#TODO Verify argument values #TODO Verify argument values
my $color = $arg; my $color = $arg;
@ -562,6 +610,16 @@ sub SHCdev_Set($@)
} }
readingsSingleUpdate($hash, "state", "set-coloranimation", 1); readingsSingleUpdate($hash, "state", "set-coloranimation", 1);
SHCdev_Send($hash); SHCdev_Send($hash);
} elsif ($cmd eq 'Dimmer.Brightness') {
my $brightness = $arg;
# DEBUG
# Log3 $name, 3, "$name: Args: $arg, $arg2, $arg3, $brightness";
readingsSingleUpdate($hash, "state", "set-brightness:$brightness", 1);
$parser->initPacket("Dimmer", "Brightness", "SetGet");
$parser->setField("Dimmer", "Brightness", "Brightness", $brightness);
SHCdev_Send($hash);
} else { } else {
return SetExtensions($hash, "", $name, @aa); return SetExtensions($hash, "", $name, @aa);
} }
@ -605,10 +663,10 @@ sub SHCdev_Get($@)
} }
elsif ($arg eq "all") elsif ($arg eq "all")
{ {
if ( defined($hash->{READINGS}{dins}) if ( defined($hash->{READINGS}{port})
&& defined($hash->{READINGS}{dins}{VAL})) && defined($hash->{READINGS}{port}{VAL}))
{ {
return "$name.dins => " . $hash->{READINGS}{dins}{VAL}; return "$name.port => " . $hash->{READINGS}{port}{VAL};
} }
return "Error: \"input all\" readings not yet available or not supported by device"; return "Error: \"input all\" readings not yet available or not supported by device";
} }
@ -676,7 +734,7 @@ sub SHCdev_Send($)
<h3>SHCdev</h3> <h3>SHCdev</h3>
<ul> <ul>
SHC is the device module that supports several device types available SHC is the device module that supports several device types available
at <a href="http://http://www.smarthomatic.org">www.smarthomatic.org</a>.<br><br> at <a href="http://www.smarthomatic.org">www.smarthomatic.org</a>.<br><br>
These device are connected to the FHEM server through the SHC base station (<a href="#SHC">SHC</a>).<br><br> These device are connected to the FHEM server through the SHC base station (<a href="#SHC">SHC</a>).<br><br>
Currently supported are:<br> Currently supported are:<br>
@ -684,6 +742,8 @@ sub SHCdev_Send($)
<li>EnvSensor</li> <li>EnvSensor</li>
<li>PowerSwitch</li> <li>PowerSwitch</li>
<li>Dimmer</li> <li>Dimmer</li>
<li>RGBDimmer</li>
<li>SoilMoistureMeter</li>
</ul><br> </ul><br>
<a name="SHCdev_Define"></a> <a name="SHCdev_Define"></a>
@ -707,10 +767,10 @@ sub SHCdev_Send($)
<b>Set</b> <b>Set</b>
<ul> <ul>
<li>on<br> <li>on<br>
Supported by Dimmer and PowerSwitch. Supported by Dimmer and PowerSwitch (on always refers to pin1).
</li><br> </li><br>
<li>off<br> <li>off<br>
Supported by Dimmer, PowerSwitch. Supported by Dimmer and PowerSwitch (off always refers to pin1).
</li><br> </li><br>
<li>pct &lt;0..100&gt;<br> <li>pct &lt;0..100&gt;<br>
Sets the brightness in percent. Supported by Dimmer. Sets the brightness in percent. Supported by Dimmer.
@ -725,12 +785,36 @@ sub SHCdev_Send($)
<li>Color &lt;ColorNumber&gt;<br> <li>Color &lt;ColorNumber&gt;<br>
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#Dimmer_Color">www.smarthomatic.org</a> 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> The color palette can be found <a href="http://www.smarthomatic.org/devices/rgb_dimmer.html">here</a>
Supported by RGB_Dimmer. Supported by RGBDimmer.
</li><br> </li><br>
<li>ColorAnimation &lt;Repeat&gt; &lt;AutoReverse&gt; &lt;Time0&gt; &lt;ColorNumber0&gt; &lt;Time1&gt; &lt;ColorNumber1&gt; ... up to 10 time/color pairs<br> <li>ColorAnimation &lt;Repeat&gt; &lt;AutoReverse&gt; &lt;Time0&gt; &lt;ColorNumber0&gt; &lt;Time1&gt; &lt;ColorNumber1&gt; ... 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> 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> The color palette can be found <a href="http://www.smarthomatic.org/devices/rgb_dimmer.html">here</a>
Supported by RGB_Dimmer. Supported by RGBDimmer.
</li><br>
<li>DigitalPin &lt;Pos&gt; &lt;On&gt;<br>
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#GPIO_DigitalPin">www.smarthomatic.org</a>
Supported by PowerSwitch.
</li><br>
<li>DigitalPinTimeout &lt;Pos&gt; &lt;On&gt; &lt;Timeout&gt;<br>
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#GPIO_DigitalPinTimeout">www.smarthomatic.org</a>
Supported by PowerSwitch.
</li><br>
<li>DigitalPort &lt;On&gt;<br>
&lt;On&gt;<br>
is a bit array (0 or 1) describing the port state. If less than eight bits were provided zero is assumed.
Example: set SHC_device DigitalPort 10110000 will set pin0, pin2 and pin3 to 1.<br>
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#GPIO_DigitalPort">www.smarthomatic.org</a>
Supported by PowerSwitch.
</li><br>
<li>DigitalPortTimeout &lt;On&gt; &lt;Timeout0&gt; .. &lt;Timeout7&gt;<br>
&lt;On&gt;<br>
is a bit array (0 or 1) describing the port state. If less than eight bits were provided zero is assumed.
Example: set SHC_device DigitalPort 10110000 will set pin0, pin2 and pin3 to 1.<br>
&lt;Timeout0&gt; .. &lt;Timeout7&gt;<br>
are the timeouts for each pin. If no timeout is provided zero is assumed.
A detailed description is available at <a href="http://www.smarthomatic.org/basics/message_catalog.html#GPIO_DigitalPortTimeout">www.smarthomatic.org</a>
Supported by PowerSwitch.
</li><br> </li><br>
<li><a href="#setExtensions"> set extensions</a><br> <li><a href="#setExtensions"> set extensions</a><br>
Supported by Dimmer and PowerSwitch.</li> Supported by Dimmer and PowerSwitch.</li>
@ -764,7 +848,7 @@ sub SHCdev_Send($)
<ul> <ul>
<li>devtype<br> <li>devtype<br>
The device type determines the command set, default web commands and the The device type determines the command set, default web commands and the
default devStateicon. Currently supported are: EnvSensor, Dimmer, PowerSwitch, RGB_Dimmer.<br><br> default devStateicon. Currently supported are: EnvSensor, Dimmer, PowerSwitch, RGBDimmer, SoilMoistureMeter.<br><br>
Note: If the device is not set manually, it will be determined automatically 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 on reception of a device type specific message. For example: If a

View File

@ -150,19 +150,16 @@ sub getInt($$$)
{ {
my ($byteArrayRef, $offset, $length_bits) = @_; my ($byteArrayRef, $offset, $length_bits) = @_;
# FIX ME! DOES NOT WORK WITH NEGATIVE VALUES!
$x = getUInt($byteArrayRef, $offset, $length_bits); $x = getUInt($byteArrayRef, $offset, $length_bits);
# If MSB is 1 (value is negative interpreted as signed int), if ($x >= 2 ** ($length_bits - 1))
# set all higher bits also to 1. {
if ((($x >> ($length_bits - 1)) & 1) == 1) { $x = $x - 2 ** $length_bits;
$x = $x | ~((1 << ($length_bits - 1)) - 1);
} }
$y = $x; # DEBUG print "UInt = " . $x . ", length_bits = " . length_bits . "\r\n";
return $y; return $x;
} }
# ----------- UIntValue class ----------- # ----------- UIntValue class -----------
@ -219,14 +216,14 @@ sub getValue
{ {
my ($self, $byteArrayRef, $index) = @_; my ($self, $byteArrayRef, $index) = @_;
return SHC_util::getUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits}); return SHC_util::getInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits});
} }
sub setValue sub setValue
{ {
my ($self, $byteArrayRef, $value, $index) = @_; my ($self, $byteArrayRef, $value, $index) = @_;
SHC_util::setUInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits}, $value); SHC_util::setInt($byteArrayRef, $self->{_offset} + $self->{_arrayElementBits} * $index, $self->{_bits}, $value);
} }
# ----------- BoolValue class ----------- # ----------- BoolValue class -----------

View File

@ -3,7 +3,7 @@
########################################################################## ##########################################################################
# This file is part of the smarthomatic module for FHEM. # This file is part of the smarthomatic module for FHEM.
# #
# Copyright (c) 2014 Uwe Freese # Copyright (c) 2014, 2015 Uwe Freese
# #
# You can find smarthomatic at www.smarthomatic.org. # You can find smarthomatic at www.smarthomatic.org.
# You can find FHEM at www.fhem.de. # You can find FHEM at www.fhem.de.
@ -30,11 +30,12 @@
# Receiving packets: # Receiving packets:
# ------------------ # ------------------
# 1.) Receive string from base station (over UART). # 1.) Receive string from base station (over UART).
# 2.) Parse received string: # 2.) Check CRC (last 8 characters, optional).
# $parser->parse("Packet Data: SenderID=22;..."); # 3.) Parse received string:
# 3.) Get MessageGroupName: my $grp = $parser->getMessageGroupName(); # $parser->parse("PKT:SID=22;...");
# 4.) Get MessageName: my $msg = $parser->getMessageName(); # 4.) Get MessageGroupName: my $grp = $parser->getMessageGroupName();
# 5.) Get data fields depending on MessageGroupName and MessageName, e.g. # 5.) Get MessageName: my $msg = $parser->getMessageName();
# 6.) Get data fields depending on MessageGroupName and MessageName, e.g.
# $val = $parser->getField("Temperature"); # $val = $parser->getField("Temperature");
# #
# Sending packets: # Sending packets:
@ -44,6 +45,7 @@
# 2.) Set fields: # 2.) Set fields:
# $parser->setField("PowerSwitch", "SwitchState", "TimeoutSec", 8); # $parser->setField("PowerSwitch", "SwitchState", "TimeoutSec", 8);
# 3.) Get send string: $str = $parser->getSendString($receiverID); # 3.) Get send string: $str = $parser->getSendString($receiverID);
# It includes a CRC32 as last 8 characters.
# 4.) Send string to base station (over UART). # 4.) Send string to base station (over UART).
########################################################################## ##########################################################################
# $Id$ # $Id$
@ -54,6 +56,7 @@ use strict;
use feature qw(switch); use feature qw(switch);
use XML::LibXML; use XML::LibXML;
use SHC_datafields; use SHC_datafields;
use Digest::CRC qw(crc32); # linux packet libdigest-crc-perl
# Hash for data field definitions. # Hash for data field definitions.
my %dataFields = (); my %dataFields = ();
@ -250,10 +253,10 @@ sub parse
if ( if (
( (
$msg =~ $msg =~
/^Packet Data: SenderID=(\d*);PacketCounter=(\d*);MessageType=(\d*);MessageGroupID=(\d*);MessageID=(\d*);MessageData=([^;]*);.*/ /^PKT:SID=(\d+);PC=(\d+);MT=(\d+);MGID=(\d+);MID=(\d+);MD=([^;]+);.*/
) )
|| ($msg =~ || ($msg =~
/^Packet Data: SenderID=(\d*);PacketCounter=(\d*);MessageType=(\d*);AckSenderID=\d*;AckPacketCounter=\d*;Error=\d*;MessageGroupID=(\d*);MessageID=(\d*);MessageData=([^;]*);.*/ /^PKT:SID=(\d+);PC=(\d+);MT=(\d+);ASID=\d+;APC=\d+;E=\d+;MGID=(\d+);MID=(\d+);MD=([^;]+);.*/
) )
) )
{ {
@ -311,6 +314,9 @@ sub getMessageData
$res .= sprintf("%02X", $_); $res .= sprintf("%02X", $_);
} }
# strip trailing zeros (pairwise)
$res =~ s/(00)+$//;
return $res; return $res;
} else { } else {
return $self->{_messageData}; return $self->{_messageData};
@ -365,8 +371,8 @@ sub setField
$obj->setValue(\@msgData, $value, $index); $obj->setValue(\@msgData, $value, $index);
} }
# sKK01RRRRGGMMDD # cKK01RRRRGGMMDD{CRC32}
# s0001003D3C0164 = SET Dimmer Switch Brightness 50% # c0001003D3C0164 = SET Dimmer Switch Brightness 50%
sub getSendString sub getSendString
{ {
my ($self, $receiverID, $aesKeyNr) = @_; my ($self, $receiverID, $aesKeyNr) = @_;
@ -382,13 +388,15 @@ sub getSendString
$aesKeyNr = 0; $aesKeyNr = 0;
} }
my $s = "s" my $s = "c"
. sprintf("%02X", $aesKeyNr) . sprintf("%02X", $aesKeyNr)
. sprintf("%02X", $self->{_messageTypeID}) . sprintf("%02X", $self->{_messageTypeID})
. sprintf("%04X", $receiverID) . sprintf("%04X", $receiverID)
. sprintf("%02X", $self->{_messageGroupID}) . sprintf("%02X", $self->{_messageGroupID})
. sprintf("%02X", $self->{_messageID}) . sprintf("%02X", $self->{_messageID})
. getMessageData(); . getMessageData();
return $s . sprintf("%08x", crc32($s));
} }
1; 1;

View File

@ -190,7 +190,7 @@
<MessageType>0</MessageType> <MessageType>0</MessageType>
<MessageType>8</MessageType> <MessageType>8</MessageType>
<MessageType>10</MessageType> <MessageType>10</MessageType>
<Validity>test</Validity> <Validity>deprecated</Validity>
<UIntValue> <UIntValue>
<ID>Major</ID> <ID>Major</ID>
<Description>Different major version means incompatible changes.</Description> <Description>Different major version means incompatible changes.</Description>
@ -220,6 +220,76 @@
<MaxVal>4294967295</MaxVal> <MaxVal>4294967295</MaxVal>
</UIntValue> </UIntValue>
</Message> </Message>
<Message>
<Name>DeviceInfo</Name>
<Description>Reports DeviceType and current firmware version. Version information is only available when set in source code, which is usually only done for official builds by the build robot.</Description>
<MessageID>2</MessageID>
<MessageType>0</MessageType>
<MessageType>8</MessageType>
<MessageType>10</MessageType>
<Validity>test</Validity>
<EnumValue>
<ID>DeviceType</ID>
<Description>The DeviceType can be used to adapt the behavior or representation of the SHC device at the server software (e.g. FHEM).</Description>
<Bits>8</Bits>
<Element>
<Value>0</Value>
<Name>BaseStation</Name>
</Element>
<Element>
<Value>20</Value>
<Name>EnvSensor</Name>
</Element>
<Element>
<Value>40</Value>
<Name>PowerSwitch</Name>
</Element>
<Element>
<Value>50</Value>
<Name>RGBDimmer</Name>
</Element>
<Element>
<Value>60</Value>
<Name>Dimmer</Name>
</Element>
<Element>
<Value>70</Value>
<Name>SoilMoistureMeter</Name>
</Element>
<Element>
<Value>80</Value>
<Name>Thermostat</Name>
</Element>
</EnumValue>
<UIntValue>
<ID>VersionMajor</ID>
<Description>Different major version means incompatible changes.</Description>
<Bits>8</Bits>
<MinVal>0</MinVal>
<MaxVal>255</MaxVal>
</UIntValue>
<UIntValue>
<ID>VersionMinor</ID>
<Description>Different minor number means new functionality without breaking compatibility.</Description>
<Bits>8</Bits>
<MinVal>0</MinVal>
<MaxVal>255</MaxVal>
</UIntValue>
<UIntValue>
<ID>VersionPatch</ID>
<Description>The patch version is changed when backwards-compatible bug fixes are made.</Description>
<Bits>8</Bits>
<MinVal>0</MinVal>
<MaxVal>255</MaxVal>
</UIntValue>
<UIntValue>
<ID>VersionHash</ID>
<Description>The beginning of the revision ID hash (as reported by Git).</Description>
<Bits>32</Bits>
<MinVal>0</MinVal>
<MaxVal>4294967295</MaxVal>
</UIntValue>
</Message>
<Message> <Message>
<Name>BatteryStatus</Name> <Name>BatteryStatus</Name>
<Description>Tells the current battery status in percent. Please note that the "Get" may not be answered because a device does not listen to requests.</Description> <Description>Tells the current battery status in percent. Please note that the "Get" may not be answered because a device does not listen to requests.</Description>
@ -242,8 +312,8 @@
<Description>This group contains messages for general I/O functions. The meaning of the values is not known to the SHC devices. It depends on the connected parts (e.g. switches). The values have to be processed by the user/server software appropriately.</Description> <Description>This group contains messages for general I/O functions. The meaning of the values is not known to the SHC devices. It depends on the connected parts (e.g. switches). The values have to be processed by the user/server software appropriately.</Description>
<MessageGroupID>1</MessageGroupID> <MessageGroupID>1</MessageGroupID>
<Message> <Message>
<Name>DigitalPin</Name> <Name>DigitalPort</Name>
<Description>This is the state of up to 8 pins.</Description> <Description>This is the state of the complete digital port, containing up to 8 pins.</Description>
<MessageID>1</MessageID> <MessageID>1</MessageID>
<MessageType>0</MessageType> <MessageType>0</MessageType>
<MessageType>1</MessageType> <MessageType>1</MessageType>
@ -261,8 +331,8 @@
</Array> </Array>
</Message> </Message>
<Message> <Message>
<Name>AnalogPin</Name> <Name>DigitalPortTimeout</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> <Description>This is the state of the complete digital port, containing up to 8 pins, including a timeout value per pin.</Description>
<MessageID>2</MessageID> <MessageID>2</MessageID>
<MessageType>0</MessageType> <MessageType>0</MessageType>
<MessageType>1</MessageType> <MessageType>1</MessageType>
@ -271,15 +341,91 @@
<MessageType>9</MessageType> <MessageType>9</MessageType>
<MessageType>10</MessageType> <MessageType>10</MessageType>
<Validity>test</Validity> <Validity>test</Validity>
<Array>
<Length>8</Length>
<BoolValue>
<ID>On</ID>
<Description>Tells if the pin is on (at high level) or not (low level).</Description>
</BoolValue>
<UIntValue>
<ID>TimeoutSec</ID>
<Description>The time after which the switch is automatically toggled again. Use 0 to disable this.</Description>
<Bits>16</Bits>
<MinVal>0</MinVal>
<MaxVal>65535</MaxVal>
</UIntValue>
</Array>
</Message>
<Message>
<Name>DigitalPin</Name>
<Description>This represents the state of one pin of the digital port.</Description>
<MessageID>5</MessageID>
<MessageType>0</MessageType>
<MessageType>1</MessageType>
<MessageType>2</MessageType>
<MessageType>8</MessageType>
<MessageType>9</MessageType>
<MessageType>10</MessageType>
<Validity>test</Validity>
<UIntValue>
<ID>Pos</ID>
<Description>The number of the pin in the port.</Description>
<Bits>3</Bits>
<MinVal>0</MinVal>
<MaxVal>7</MaxVal>
</UIntValue>
<BoolValue>
<ID>On</ID>
<Description>Tells if the pin is on (at high level) or not (low level).</Description>
</BoolValue>
</Message>
<Message>
<Name>DigitalPinTimeout</Name>
<Description>This represents the state of one pin of the digital port, including a timeout value.</Description>
<MessageID>6</MessageID>
<MessageType>0</MessageType>
<MessageType>1</MessageType>
<MessageType>2</MessageType>
<MessageType>8</MessageType>
<MessageType>9</MessageType>
<MessageType>10</MessageType>
<Validity>test</Validity>
<UIntValue>
<ID>Pos</ID>
<Description>The number of the pin in the port.</Description>
<Bits>3</Bits>
<MinVal>0</MinVal>
<MaxVal>7</MaxVal>
</UIntValue>
<BoolValue>
<ID>On</ID>
<Description>Tells if the pin is on (at high level) or not (low level).</Description>
</BoolValue>
<UIntValue>
<ID>TimeoutSec</ID>
<Description>The time after which the switch is automatically toggled again. Use 0 to disable this.</Description>
<Bits>16</Bits>
<MinVal>0</MinVal>
<MaxVal>65535</MaxVal>
</UIntValue>
</Message>
<Message>
<Name>AnalogPort</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>10</MessageID>
<MessageType>0</MessageType>
<MessageType>1</MessageType>
<MessageType>2</MessageType>
<MessageType>8</MessageType>
<MessageType>9</MessageType>
<MessageType>10</MessageType>
<Validity>test</Validity>
<Array> <Array>
<Length>8</Length> <Length>8</Length>
<BoolValue> <BoolValue>
<ID>On</ID> <ID>On</ID>
<Description>Tells if the pin is on (voltage over trigger threshold) or not.</Description> <Description>Tells if the pin is on (voltage over trigger threshold) or not.</Description>
</BoolValue> </BoolValue>
</Array>
<Array>
<Length>8</Length>
<UIntValue> <UIntValue>
<ID>Voltage</ID> <ID>Voltage</ID>
<Description>This is the voltage level in mV.</Description> <Description>This is the voltage level in mV.</Description>
@ -356,6 +502,22 @@
<MaxVal>32767</MaxVal> <MaxVal>32767</MaxVal>
</IntValue> </IntValue>
</Message> </Message>
<Message>
<Name>Humidity</Name>
<Description>This is a message containing humidity.</Description>
<MessageID>4</MessageID>
<MessageType>0</MessageType>
<MessageType>8</MessageType>
<MessageType>10</MessageType>
<Validity>test</Validity>
<UIntValue>
<ID>Humidity</ID>
<Description>relative humidity permill, 0..1000 (other values not defined)</Description>
<Bits>10</Bits>
<MinVal>0</MinVal>
<MaxVal>1000</MaxVal>
</UIntValue>
</Message>
</MessageGroup> </MessageGroup>
<MessageGroup> <MessageGroup>
<Name>Environment</Name> <Name>Environment</Name>
@ -408,7 +570,7 @@
<MessageType>8</MessageType> <MessageType>8</MessageType>
<MessageType>9</MessageType> <MessageType>9</MessageType>
<MessageType>10</MessageType> <MessageType>10</MessageType>
<Validity>test</Validity> <Validity>deprecated</Validity>
<BoolValue> <BoolValue>
<ID>On</ID> <ID>On</ID>
<Description>Tells if the switch is on (active).</Description> <Description>Tells if the switch is on (active).</Description>
@ -431,7 +593,7 @@
<MessageType>8</MessageType> <MessageType>8</MessageType>
<MessageType>9</MessageType> <MessageType>9</MessageType>
<MessageType>10</MessageType> <MessageType>10</MessageType>
<Validity>test</Validity> <Validity>deprecated</Validity>
<Array> <Array>
<Length>8</Length> <Length>8</Length>
<BoolValue> <BoolValue>