2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 16:56:54 +00:00

00_ElsnerWS: alarm and custom commands execution added; function call switched to "use DevIo"

git-svn-id: https://svn.fhem.de/fhem/trunk@22604 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
klaus.schauer 2020-08-15 07:24:43 +00:00
parent a6bb1f79b6
commit 8285b22d44

View File

@ -6,12 +6,8 @@ package main;
use strict; use strict;
use warnings; use warnings;
use DevIo;
use Time::HiRes qw(gettimeofday usleep); use Time::HiRes qw(gettimeofday usleep);
if( $^O =~ /Win/ ) {
require Win32::SerialPort;
} else {
require Device::SerialPort;
}
sub ElsnerWS_Checksum($$); sub ElsnerWS_Checksum($$);
sub ElsnerWS_Define($$$); sub ElsnerWS_Define($$$);
@ -20,10 +16,26 @@ sub ElsnerWS_Initialize($);
sub ElsnerWS_Read($); sub ElsnerWS_Read($);
sub ElsnerWS_Ready($); sub ElsnerWS_Ready($);
# trigger values for down and up commands
my %customCmdTrigger = ('dayNight' => ['night', 'day'],
'isRaining' => ['no', 'yes'],
'isStormy' => ['no', 'yes'],
'isSunny' => ['yes', 'no'],
'isSunnyEast' => ['yes', 'no'],
'isSunnySouth' => ['yes', 'no'],
'isSunnyWest' => ['yes', 'no'],
'isWindy' => ['no', 'yes']);
my %customCmdPeriod =(once => -1,
threeTimes => -3,
3 => 3,
10 => 10,
180 => 180,
600 => 600);
my %specials;
# Init # Init
sub ElsnerWS_Initialize($) { sub ElsnerWS_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
require "$attr{global}{modpath}/FHEM/DevIo.pm";
# Provider # Provider
$hash->{ReadFn} = "ElsnerWS_Read"; $hash->{ReadFn} = "ElsnerWS_Read";
@ -35,10 +47,16 @@ sub ElsnerWS_Initialize($) {
$hash->{DeleteFn} = "ElsnerWS_Delete"; $hash->{DeleteFn} = "ElsnerWS_Delete";
$hash->{NotifyFn} = "ElsnerWS_Notify"; $hash->{NotifyFn} = "ElsnerWS_Notify";
$hash->{AttrFn} = "ElsnerWS_Attr"; $hash->{AttrFn} = "ElsnerWS_Attr";
$hash->{AttrList} = "brightnessDayNight brightnessDayNightCtrl brightnessDayNightDelay " . $hash->{AttrList} = "brightnessDayNight brightnessDayNightCtrl:select,custom,sensor brightnessDayNightDelay " .
"brightnessSunny brightnessSunnySouth brightnessSunnyWest brightnessSunnyEast " . "brightnessSunny brightnessSunnySouth brightnessSunnyWest brightnessSunnyEast " .
"brightnessSunnyDelay brightnessSunnySouthDelay brightnessSunnyWestDelay brightnessSunnyEastDelay " . "brightnessSunnyDelay brightnessSunnySouthDelay brightnessSunnyWestDelay brightnessSunnyEastDelay " .
"timeEvent:no,yes updateGlobalAttr:no,yes " . "customCmdAlarmOff:textField-long customCmdAlarmOn:textField-long " .
"customCmdDown:textField-long customCmdDownPeriod:select," . join(",", sort keys %customCmdPeriod) . " " .
"customCmdDownTrigger:multiple-strict," . join(",", sort keys %customCmdTrigger) . " " .
"customCmdPriority:select,down,up " .
"customCmdUp:textField-long customCmdUpPeriod:select," . join(",", sort keys %customCmdPeriod) . " " .
"customCmdUpTrigger:multiple-strict," . join(",", sort keys %customCmdTrigger) . " " .
"signOfLife:select,off,on signOfLifeInterval:slider,1,1,15 timeEvent:select,no,yes updateGlobalAttr:select,no,yes " .
"windSpeedWindy windSpeedStormy windSpeedWindyDelay windSpeedStormyDelay " . "windSpeedWindy windSpeedStormy windSpeedWindyDelay windSpeedStormyDelay " .
$readingFnAttributes; $readingFnAttributes;
$hash->{parseParams} = 1; $hash->{parseParams} = 1;
@ -213,6 +231,10 @@ sub ElsnerWS_Read($) {
$hash->{helper}{wind}{windGustNumArrayElements} = ElsnerWS_updateArrayElement($hash, 'windGust', $windGust20s, 'wind', 600); $hash->{helper}{wind}{windGustNumArrayElements} = ElsnerWS_updateArrayElement($hash, 'windGust', $windGust20s, 'wind', 600);
my ($windGustAvg10min, $windGustMin10min, $windGustMax10min) = ElsnerWS_SMA($hash, 'windGust', $windGust20s, 'windGustAvg10min', 'windGustMax10min', 'windGustMin10min', 'wind', 600); my ($windGustAvg10min, $windGustMin10min, $windGustMax10min) = ElsnerWS_SMA($hash, 'windGust', $windGust20s, 'windGustAvg10min', 'windGustMax10min', 'windGustMin10min', 'wind', 600);
my $windGust10min = $windGustMax10min >= 5.144 ? $windGustMax10min : $windAvg2min; my $windGust10min = $windGustMax10min >= 5.144 ? $windGustMax10min : $windAvg2min;
$windAvg2min = sprintf("%0.1f", $windAvg2min);
$windGust10min = sprintf("%0.1f", $windGust10min);
$windGustCurrent = sprintf("%0.1f", $windGustCurrent);
$windPeak10min = sprintf("%0.1f", $windPeak10min);
my @sunlight = ($sunSouth, $sunWest, $sunEast); my @sunlight = ($sunSouth, $sunWest, $sunEast);
my ($sunMin, $sunMax) = (sort {$a <=> $b} @sunlight)[0,-1]; my ($sunMin, $sunMax) = (sort {$a <=> $b} @sunlight)[0,-1];
$sunSouth = $sunSouth == 0 ? $brightness : $sunSouth; $sunSouth = $sunSouth == 0 ? $brightness : $sunSouth;
@ -237,40 +259,57 @@ sub ElsnerWS_Read($) {
while($windSpeed > $windStrength[$windStrength] && $windStrength <= @windStrength + 1) { while($windSpeed > $windStrength[$windStrength] && $windStrength <= @windStrength + 1) {
$windStrength ++; $windStrength ++;
} }
my $isSunny = ElsnerWS_swayCtrl($hash, "isSunny", $brightness, "brightnessSunny", "brightnessSunnyDelay", 20000, 40000, 120, 30, 'no', 'yes');
my $isSunnySouth = ElsnerWS_swayCtrl($hash, "isSunnySouth", $sunSouth, "brightnessSunnySouth", "brightnessSunnySouthDelay", 20000, 40000, 120, 30, 'no', 'yes');
my $isSunnyWest = ElsnerWS_swayCtrl($hash, "isSunnyWest", $sunWest, "brightnessSunnyWest", "brightnessSunnyWestDelay", 20000, 40000, 120, 30, 'no', 'yes');
my $isSunnyEast = ElsnerWS_swayCtrl($hash, "isSunnyEast", $sunEast, "brightnessSunnyEast", "brightnessSunnyEastDelay", 20000, 40000, 120, 30, 'no', 'yes');
my $isStormy = ElsnerWS_swayCtrl($hash, "isStormy", $windSpeed, "windSpeedStormy", "windSpeedStormyDelay", 13.9, 17.2, 60, 3, 'no', 'yes');
my $isWindy = ElsnerWS_swayCtrl($hash, "isWindy", $windSpeed, "windSpeedWindy", "windSpeedWindyDelay", 1.6, 3.4, 60, 3, 'no', 'yes');
if (!exists($hash->{helper}{timer}{lastUpdate}) || $hash->{helper}{timer}{lastUpdate} < gettimeofday() - 60) { if (!exists($hash->{helper}{timer}{lastUpdate}) || $hash->{helper}{timer}{lastUpdate} < gettimeofday() - 60) {
# update every 60 sec # update every 60 sec
readingsBulkUpdateIfChanged($hash, "windGustCurrent", sprintf("%0.1f", $windGustCurrent)); readingsBulkUpdateIfChanged($hash, "windAvg2min", $windAvg2min);
readingsBulkUpdateIfChanged($hash, "windAvg2min", sprintf("%0.1f", $windAvg2min)); readingsBulkUpdateIfChanged($hash, "windGust10min", $windGust10min);
readingsBulkUpdateIfChanged($hash, "windGust10min", sprintf("%0.1f", $windGust10min)); readingsBulkUpdateIfChanged($hash, "windGustCurrent", $windGustCurrent);
readingsBulkUpdateIfChanged($hash, "windPeak10min", sprintf("%0.1f", $windPeak10min)); readingsBulkUpdateIfChanged($hash, "windPeak10min", $windPeak10min);
$hash->{helper}{timer}{lastUpdate} = gettimeofday(); $hash->{helper}{timer}{lastUpdate} = gettimeofday();
} }
if (exists $hash->{helper}{timer}{heartbeat}) { if (exists $hash->{helper}{timer}{heartbeat}) {
readingsBulkUpdateIfChanged($hash, "dayNight", $twilightFlag); readingsBulkUpdateIfChanged($hash, "dayNight", $twilightFlag);
readingsBulkUpdateIfChanged($hash, "isRaining", $isRaining); readingsBulkUpdateIfChanged($hash, "isRaining", $isRaining);
readingsBulkUpdateIfChanged($hash, "windStrength", $windStrength); readingsBulkUpdateIfChanged($hash, "windStrength", $windStrength);
readingsBulkUpdateIfChanged($hash, "isSunny", ElsnerWS_swayCtrl($hash, "isSunny", $brightness, "brightnessSunny", "brightnessSunnyDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdateIfChanged($hash, "isSunny", $isSunny);
readingsBulkUpdateIfChanged($hash, "isSunnySouth", ElsnerWS_swayCtrl($hash, "isSunnySouth", $sunSouth, "brightnessSunnySouth", "brightnessSunnySouthDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdateIfChanged($hash, "isSunnySouth", $isSunnySouth);
readingsBulkUpdateIfChanged($hash, "isSunnyWest", ElsnerWS_swayCtrl($hash, "isSunnyWest", $sunWest, "brightnessSunnyWest", "brightnessSunnyWestDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdateIfChanged($hash, "isSunnyWest", $isSunnyWest);
readingsBulkUpdateIfChanged($hash, "isSunnyEast", ElsnerWS_swayCtrl($hash, "isSunnyEast", $sunEast, "brightnessSunnyEast", "brightnessSunnyEastDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdateIfChanged($hash, "isSunnyEast", $isSunnyEast);
readingsBulkUpdateIfChanged($hash, "isStormy", ElsnerWS_swayCtrl($hash, "isStormy", $windSpeed, "windSpeedStormy", "windSpeedStormyDelay", 13.9, 17.2, 60, 3, 'no', 'yes')); readingsBulkUpdateIfChanged($hash, "isStormy", $isStormy);
readingsBulkUpdateIfChanged($hash, "isWindy", ElsnerWS_swayCtrl($hash, "isWindy", $windSpeed, "windSpeedWindy", "windSpeedWindyDelay", 1.6, 3.4, 60, 3, 'no', 'yes')); readingsBulkUpdateIfChanged($hash, "isWindy", $isWindy);
} else { } else {
readingsBulkUpdate($hash, "dayNight", $twilightFlag); readingsBulkUpdate($hash, "dayNight", $twilightFlag);
readingsBulkUpdate($hash, "isRaining", $isRaining); readingsBulkUpdate($hash, "isRaining", $isRaining);
readingsBulkUpdate($hash, "windStrength", $windStrength); readingsBulkUpdate($hash, "windStrength", $windStrength);
readingsBulkUpdate($hash, "isSunny", ElsnerWS_swayCtrl($hash, "isSunny", $brightness, "brightnessSunny", "brightnessSunnyDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdate($hash, "isSunny", $isSunny);
readingsBulkUpdate($hash, "isSunnySouth", ElsnerWS_swayCtrl($hash, "isSunnySouth", $sunSouth, "brightnessSunnySouth", "brightnessSunnySouthDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdate($hash, "isSunnySouth", $isSunnySouth);
readingsBulkUpdate($hash, "isSunnyWest", ElsnerWS_swayCtrl($hash, "isSunnyWest", $sunWest, "brightnessSunnyWest", "brightnessSunnyWestDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdate($hash, "isSunnyWest", $isSunnyWest);
readingsBulkUpdate($hash, "isSunnyEast", ElsnerWS_swayCtrl($hash, "isSunnyEast", $sunEast, "brightnessSunnyEast", "brightnessSunnyEastDelay", 20000, 40000, 120, 30, 'no', 'yes')); readingsBulkUpdate($hash, "isSunnyEast", $isSunnyEast);
readingsBulkUpdate($hash, "isStormy", ElsnerWS_swayCtrl($hash, "isStormy", $windSpeed, "windSpeedStormy", "windSpeedStormyDelay", 13.9, 17.2, 60, 3, 'no', 'yes')); readingsBulkUpdate($hash, "isStormy", $isStormy);
readingsBulkUpdate($hash, "isWindy", ElsnerWS_swayCtrl($hash, "isWindy", $windSpeed, "windSpeedWindy", "windSpeedWindyDelay", 1.6, 3.4, 60, 3, 'no', 'yes')); readingsBulkUpdate($hash, "isWindy", $isWindy);
} }
readingsBulkUpdateIfChanged($hash, "state", "T: " . $temperature . readingsBulkUpdateIfChanged($hash, "state", "T: " . $temperature .
" B: " . $brightness . " B: " . $brightness .
" W: " . $windSpeed . " W: " . $windSpeed .
" IR: " . $isRaining); " IR: " . $isRaining);
my $weekday = '';
my $date = '';
my $timeZone = '';
my $time = '';
my $hemisphere = '';
my $latitude = '';
my $longitude = '';
my $sunAzimuth = '';
my $sunElevation = '';
my $twilight = '';
if (defined $zdata) { if (defined $zdata) {
if ($packetType eq '47') { if ($packetType eq '47') {
# packet type GPS # packet type GPS
@ -294,11 +333,14 @@ sub ElsnerWS_Read($) {
readingsDelete($hash, 'time'); readingsDelete($hash, 'time');
delete $hash->{GPS_TIME}; delete $hash->{GPS_TIME};
} else { } else {
readingsBulkUpdateIfChanged($hash, "weekday", $weekday{$weekday}); $weekday = $weekday{$weekday};
readingsBulkUpdateIfChanged($hash, "date", '20' . pack('H*', $year) . '-' . pack('H*', $month) . '-' . pack('H*', $day)); $date = '20' . pack('H*', $year) . '-' . pack('H*', $month) . '-' . pack('H*', $day);
readingsBulkUpdateIfChanged($hash, "timeZone", 'UTC'); $timeZone = 'UTC';
#readingsBulkUpdateIfChanged($hash, "time", pack('H*', $hour) . ':' . pack('H*', $minute) . ':' . pack('H*', $second)); $time = pack('H*', $hour) . ':' . pack('H*', $minute) . ':' . pack('H*', $second);
$hash->{GPS_TIME} = pack('H*', $hour) . ':' . pack('H*', $minute) . ':' . pack('H*', $second); readingsBulkUpdateIfChanged($hash, "weekday", $weekday);
readingsBulkUpdateIfChanged($hash, "date", $date);
readingsBulkUpdateIfChanged($hash, "timeZone", $timeZone);
$hash->{GPS_TIME} = $time;
} }
if ($gpsStatus eq '30') { if ($gpsStatus eq '30') {
# GPS error # GPS error
@ -309,26 +351,33 @@ sub ElsnerWS_Read($) {
readingsDelete($hash, 'sunElevation'); readingsDelete($hash, 'sunElevation');
readingsDelete($hash, 'twilight'); readingsDelete($hash, 'twilight');
} else { } else {
readingsBulkUpdateIfChanged($hash, "sunAzimuth", sprintf("%0.1f", pack('H*', $sunAzimuth))); $hemisphere = $latitudeSign eq '4E' ? "north" : "south";
$latitude = sprintf("%0.1f", ($latitudeSign eq '4E' ? '' : '-') . pack('H*', $latitude));
$longitude = sprintf("%0.1f", ($longitudeSign eq '4F' ? '' : '-') . pack('H*', $longitude));
$sunAzimuth = sprintf("%0.1f", pack('H*', $sunAzimuth));
$sunElevation = ($sunElevationSign eq '2B' ? '' : '-') . pack('H*', $sunElevation); $sunElevation = ($sunElevationSign eq '2B' ? '' : '-') . pack('H*', $sunElevation);
my $twilight = ($sunElevation + 12) / 18 * 100; $twilight = ($sunElevation + 12) / 18 * 100;
$twilight = 0 if ($twilight < 0); $twilight = 0 if ($twilight < 0);
$twilight = 100 if ($twilight > 100); $twilight = 100 if ($twilight > 100);
readingsBulkUpdateIfChanged($hash, "sunElevation", sprintf("%0.1f", $sunElevation)); $twilight = int($twilight);
readingsBulkUpdateIfChanged($hash, "twilight", int($twilight)); $sunElevation = sprintf("%0.1f", $sunElevation);
readingsBulkUpdateIfChanged($hash, "longitude", sprintf("%0.1f", ($longitudeSign eq '4F' ? '' : '-') . pack('H*', $longitude))); readingsBulkUpdateIfChanged($hash, "sunAzimuth", $sunAzimuth);
readingsBulkUpdateIfChanged($hash, "sunElevation", $sunElevation);
readingsBulkUpdateIfChanged($hash, "twilight", $twilight);
readingsBulkUpdateIfChanged($hash, "longitude", $longitude);
if (AttrVal($name, "updateGlobalAttr", 'no') eq 'yes') { if (AttrVal($name, "updateGlobalAttr", 'no') eq 'yes') {
$attr{global}{longitude} = sprintf("%0.1f", ($longitudeSign eq '4F' ? '' : '-') . pack('H*', $longitude)); $attr{global}{longitude} = $longitude;
} }
readingsBulkUpdateIfChanged($hash, "latitude", sprintf("%0.1f", ($latitudeSign eq '4E' ? '' : '-') . pack('H*', $latitude))); readingsBulkUpdateIfChanged($hash, "latitude", $latitude);
if (AttrVal($name, "updateGlobalAttr", 'no') eq 'yes') { if (AttrVal($name, "updateGlobalAttr", 'no') eq 'yes') {
$attr{global}{latitude} = sprintf("%0.1f", ($latitudeSign eq '4E' ? '' : '-') . pack('H*', $latitude)); $attr{global}{latitude} = $latitude;
} }
readingsBulkUpdateIfChanged($hash, "hemisphere", ($latitudeSign eq '4E' ? "north" : "south")); readingsBulkUpdateIfChanged($hash, "hemisphere", $hemisphere);
} }
} elsif ($packetType eq '57') { } elsif ($packetType eq '57') {
# packet type CET # packet type CET
$hash->{MODEL} = 'CET'; $hash->{MODEL} = 'CET';
my ($weekday, $day, $month, $year, $hour, $minute, $second);
my %weekday = ('3F' => 'UTC_error', my %weekday = ('3F' => 'UTC_error',
'31' => 'Monday', '31' => 'Monday',
'32' => 'Tuesday', '32' => 'Tuesday',
@ -338,7 +387,7 @@ sub ElsnerWS_Read($) {
'36' => 'Saturday', '36' => 'Saturday',
'37' => 'Sunday'); '37' => 'Sunday');
$zdata =~ m/^(..)(....)(....)(....)(....)(....)(....)(..)/; $zdata =~ m/^(..)(....)(....)(....)(....)(....)(....)(..)/;
my ($weekday, $day, $month, $year, $hour, $minute, $second, $timeZone) = ($1, $2, $3, $4, $5, $6, $7, $8); ($weekday, $day, $month, $year, $hour, $minute, $second, $timeZone) = ($1, $2, $3, $4, $5, $6, $7, $8);
if ($weekday eq '3F') { if ($weekday eq '3F') {
# UTC error # UTC error
readingsDelete($hash, 'weekday'); readingsDelete($hash, 'weekday');
@ -347,10 +396,14 @@ sub ElsnerWS_Read($) {
readingsDelete($hash, 'time'); readingsDelete($hash, 'time');
delete $hash->{GPS_TIME}; delete $hash->{GPS_TIME};
} else { } else {
readingsBulkUpdateIfChanged($hash, "weekday", $weekday{$weekday}); $weekday = $weekday{$weekday};
readingsBulkUpdateIfChanged($hash, "date", '20' . pack('H*', $year) . '-' . pack('H*', $month) . '-' . pack('H*', $day)); $date = '20' . pack('H*', $year) . '-' . pack('H*', $month) . '-' . pack('H*', $day);
readingsBulkUpdateIfChanged($hash, "timeZone", $timeZone eq '4E' ? 'CET' : 'CEST'); $timeZone = $timeZone eq '4E' ? 'CET' : 'CEST';
$hash->{GPS_TIME} = pack('H*', $hour) . ':' . pack('H*', $minute) . ':' . pack('H*', $second); $time = pack('H*', $hour) . ':' . pack('H*', $minute) . ':' . pack('H*', $second);
readingsBulkUpdateIfChanged($hash, "weekday", $weekday);
readingsBulkUpdateIfChanged($hash, "date", $date);
readingsBulkUpdateIfChanged($hash, "timeZone", $timeZone);
$hash->{GPS_TIME} = $time;
} }
} }
} else { } else {
@ -359,16 +412,88 @@ sub ElsnerWS_Read($) {
readingsEndUpdate($hash, 1); readingsEndUpdate($hash, 1);
readingsSingleUpdate($hash, 'time', $hash->{GPS_TIME}, AttrVal($name, 'timeEvent', 'no') eq 'yes' ? 1 : 0) if (exists $hash->{GPS_TIME}); readingsSingleUpdate($hash, 'time', $hash->{GPS_TIME}, AttrVal($name, 'timeEvent', 'no') eq 'yes' ? 1 : 0) if (exists $hash->{GPS_TIME});
$data = $rest; $data = $rest;
readingsDelete($hash, 'alarm');
RemoveInternalTimer($hash->{helper}{timer}{alarm}) if(exists $hash->{helper}{timer}{alarm}); # custom command exec
@{$hash->{helper}{timer}{alarm}} = ($hash, 'alarm', 'dead_sensor', 1, 5, 0); %specials = ("%NAME" => $name,
InternalTimer(gettimeofday() + 1.5, 'ElsnerWS_readingsSingleUpdate', $hash->{helper}{timer}{alarm}, 0); "%TYPE" => $hash->{TYPE},
"%BRIGHTNESS" => $brightness,
"%DATE" => $date,
"%DAYNIGHT" => $twilightFlag,
"%HEMISPHERE" => $hemisphere,
"%ISRAINING" => $isRaining,
"%ISSTORMY" => $isStormy,
"%ISSUNNY" => $isSunny,
"%ISSUNNYEAST" => $isSunnyEast,
"%ISSUNNYSOUTH" => $isSunnySouth,
"%ISSUNNYWEST" => $isSunnyWest,
"%ISWINDY" => $isWindy,
"%LATITUDE" => $latitude,
"%LONGITUDE" => $longitude,
"%SUNAZIMUTH" => $sunAzimuth,
"%SUNEAST" => $sunEast,
"%SUNELAVATION" => $sunElevation,
"%SUNSOUTH" => $sunSouth,
"%SUNWEST" => $sunWest,
"%TEMPERATURE" => $temperature,
"%TIME" => $time,
"%TIMEZONE" => $timeZone,
"%TWILIGHT" => $twilight,
"%WEEKDAY" => $weekday,
"%WINDAVG2MIN" => $windAvg2min,
"%WINDGUST10MIN" => $windGust10min,
"%WINDGUSTCURRNT" => $windGustCurrent,
"%WINDPEAK10MIN" => $windPeak10min,
"%WINDSPEED" => $windSpeed,
"%WINDSTENGTH" => $windStrength);
my $customCmdDown = AttrVal($name, "customCmdDown", undef);
my $customCmdDownPeriod = AttrVal($name, "customCmdDownPeriod", 'once');
my $customCmdDownTrigger = AttrVal($name, 'customCmdDownTrigger', undef);
my $customCmdUp = AttrVal($name, "customCmdUp", undef);
my $customCmdUpPeriod = AttrVal($name, "customCmdUpPeriod", 'once');
my $customCmdUpTrigger = AttrVal($name, 'customCmdUpTrigger', undef);
#delete $hash->{helper}{customCmdDown}{do};
#delete $hash->{helper}{customCmdUp}{do};
if (defined ReadingsVal($name, 'alarm', undef)) {
my $customCmdAlarmOff = AttrVal($name, 'customCmdAlarmOff', undef);
if (defined $customCmdAlarmOff) {
$hash->{helper}{customCmdAlarmOff}{do} = 1;
ElsnerWS_CustomCmdDo($hash, 'customCmdAlarmOff', $customCmdAlarmOff, 'once');
}
readingsDelete($hash, 'alarm');
}
delete $hash->{helper}{customCmdAlarmOff};
if (AttrVal($name, "signOfLife", 'on') eq 'on') {
RemoveInternalTimer($hash->{helper}{timer}{alarm}) if(exists $hash->{helper}{timer}{alarm});
@{$hash->{helper}{timer}{alarm}} = ($hash, 'alarm', 'dead_sensor', 1, 5, 0);
InternalTimer(gettimeofday() + AttrVal($name, 'signOfLifeInterval', 3) + 0.5, 'ElsnerWS_AlarmOn', $hash->{helper}{timer}{alarm}, 0);
}
if (!exists $hash->{helper}{timer}{heartbeat}) { if (!exists $hash->{helper}{timer}{heartbeat}) {
@{$hash->{helper}{timer}{heartbeat}} = ($hash, 'heartbeat'); @{$hash->{helper}{timer}{heartbeat}} = ($hash, 'heartbeat');
RemoveInternalTimer($hash->{helper}{timer}{heartbeat}); RemoveInternalTimer($hash->{helper}{timer}{heartbeat});
InternalTimer(gettimeofday() + 600, 'ElsnerWS_cdmClearTimer', $hash->{helper}{timer}{heartbeat}, 0); InternalTimer(gettimeofday() + 600, 'ElsnerWS_cdmClearTimer', $hash->{helper}{timer}{heartbeat}, 0);
#Log3 $hash->{NAME}, 3, "ElsnerWS $hash->{NAME} ElsnerWS_readingsBulkUpdate heartbeat executed."; #Log3 $hash->{NAME}, 3, "ElsnerWS $hash->{NAME} ElsnerWS_readingsBulkUpdate heartbeat executed.";
} }
if (defined($customCmdDown) || defined($customCmdUp)) {
ElsnerWS_CustomCmdDoTrigger($hash, 'customCmdDown', $customCmdDown, AttrVal($name, 'customCmdDownTrigger', undef), 0);
ElsnerWS_CustomCmdDoTrigger($hash, 'customCmdUp', $customCmdUp, AttrVal($name, 'customCmdUpTrigger', undef), 1);
if (exists($hash->{helper}{customCmdDown}{do}) && exists($hash->{helper}{customCmdUp}{do})) {
if (AttrVal($name, 'customCmdPriority', 'up') eq 'up') {
# up command has prority
delete $hash->{helper}{customCmdDown} if (defined $customCmdDownTrigger);
} else {
# down command has prority
delete $hash->{helper}{customCmdUp} if (defined $customCmdUpTrigger);
}
}
ElsnerWS_CustomCmdDo($hash, 'customCmdDown', $customCmdDown, $customCmdDownPeriod);
ElsnerWS_CustomCmdDo($hash, 'customCmdUp', $customCmdUp, $customCmdUpPeriod);
}
} }
if(length($data) >= 4) { if(length($data) >= 4) {
$data =~ s/.*47/47/ if($data !~ m/^47(2B|2D)/); $data =~ s/.*47/47/ if($data !~ m/^47(2B|2D)/);
@ -379,7 +504,97 @@ sub ElsnerWS_Read($) {
return; return;
} }
##### sub ElsnerWS_CustomCmdDoTrigger($$$$$) {
# set do trigger
my ($hash, $customCmdName, $customCmdVal, $customCmdTrigger, $element) = @_;
my $readingName;
if (defined($customCmdVal)) {
if (defined $customCmdTrigger) {
for (split(',', $customCmdTrigger)) {
$readingName = "%" . uc($_);
#Log3 $hash->{NAME}, 3, "ElsnerWS $hash->{NAME} $customCmdName Reading: $_ = " . $specials{$readingName} . " <=> " . $customCmdTrigger{$_}[$element];
if ($customCmdTrigger{$_}[$element] eq $specials{$readingName}) {
$hash->{helper}{$customCmdName}{do} = 1;
last;
} else {
delete $hash->{helper}{$customCmdName}{do};
}
}
# reset trigger
if (!exists $hash->{helper}{$customCmdName}{do}) {
delete $hash->{helper}{$customCmdName}{Count};
delete $hash->{helper}{$customCmdName}{Period};
delete $hash->{helper}{$customCmdName};
}
} else {
# custom command always executed
$hash->{helper}{$customCmdName}{Count} = -1;
$hash->{helper}{$customCmdName}{Period} = -1;
$hash->{helper}{$customCmdName}{do} = 1;
}
} else {
# no custom command
delete $hash->{helper}{$customCmdName}{Count};
delete $hash->{helper}{$customCmdName}{do};
delete $hash->{helper}{$customCmdName}{Period};
delete $hash->{helper}{$customCmdName};
}
return;
}
sub ElsnerWS_CustomCmdDo($$$$) {
my ($hash, $customCmdName, $customCmd, $customCmdPeriod) = @_;
my $name = $hash->{NAME};
#Log3 $name, 3, "ElsnerWS $name $customCmdName do: $hash->{helper}{$customCmdName}{do} Count: $hash->{helper}{$customCmdName}{Count}";
#Log3 $name, 3, "ElsnerWS $name $customCmdName Count: $hash->{helper}{$customCmdName}{Count} Period: $hash->{helper}{$customCmdName}{Period} <> $customCmdPeriod{$customCmdPeriod}";
if (exists $hash->{helper}{$customCmdName}{do}) {
if (!exists($hash->{helper}{$customCmdName}{Period}) || $hash->{helper}{$customCmdName}{Period} != $customCmdPeriod{$customCmdPeriod}) {
$hash->{helper}{$customCmdName}{Period} = $customCmdPeriod{$customCmdPeriod};
$hash->{helper}{$customCmdName}{Count} = $customCmdPeriod{$customCmdPeriod};
}
#Log3 $name, 3, "ElsnerWS $name $customCmdName Count: $hash->{helper}{$customCmdName}{Count}";
if ($hash->{helper}{$customCmdName}{Count} < -1) {
$hash->{helper}{$customCmdName}{Count} ++;
} elsif ($hash->{helper}{$customCmdName}{Count} == -1) {
$hash->{helper}{$customCmdName}{Count} = 0;
} elsif ($hash->{helper}{$customCmdName}{Count} == 0) {
delete $hash->{helper}{$customCmdName}{do};
} elsif ($hash->{helper}{$customCmdName}{Count} == $customCmdPeriod{$customCmdPeriod}) {
$hash->{helper}{$customCmdName}{Count} --;
} elsif ($hash->{helper}{$customCmdName}{Count} > 1) {
$hash->{helper}{$customCmdName}{Count} --;
delete $hash->{helper}{$customCmdName}{do};
} elsif ($hash->{helper}{$customCmdName}{Count} == 1) {
$hash->{helper}{$customCmdName}{Count} = $customCmdPeriod{$customCmdPeriod};
delete $hash->{helper}{$customCmdName}{do};
} else {
delete $hash->{helper}{$customCmdName}{do};
}
if (exists $hash->{helper}{$customCmdName}{do}) {
$customCmd = EvalSpecials($customCmd, %specials);
my $ret = AnalyzeCommandChain(undef, $customCmd);
Log3 $name, 2, "ElsnerWS $name $customCmdName ERROR: $ret" if($ret);
}
}
return;
}
sub ElsnerWS_AlarmOn($) {
my ($readingParam) = @_;
my ($hash, $readingName, $readingVal, $ctrl, $log, $clear) = @$readingParam;
if (defined $hash) {
my $customCmdAlarmOn = AttrVal($hash->{NAME}, 'customCmdAlarmOn', undef);
if (defined $customCmdAlarmOn) {
$hash->{helper}{customCmdAlarmOn}{do} = 1;
ElsnerWS_CustomCmdDo($hash, 'customCmdAlarmOn', $customCmdAlarmOn, 'once');
delete $hash->{helper}{customCmdAlarmOn};
}
readingsSingleUpdate($hash, $readingName, $readingVal, $ctrl) ;
Log3 $hash->{NAME}, $log, " ElsnerWS " . $hash->{NAME} . " EVENT $readingName: $readingVal" if ($log);
}
return;
}
sub ElsnerWS_updateArrayElement($$$$$) { sub ElsnerWS_updateArrayElement($$$$$) {
# read und update values to array # read und update values to array
my ($hash, $readingName, $readingVal, $arrayName, $numArrayElementsMax) = @_; my ($hash, $readingName, $readingVal, $arrayName, $numArrayElementsMax) = @_;
@ -597,6 +812,26 @@ sub ElsnerWS_Attr(@) {
$err = "attribute-value [$attrName] = $attrVal wrong"; $err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName"); CommandDeleteAttr(undef, "$name $attrName");
} }
} elsif ($attrName =~ m/^.*Delay$/) {
my ($attrVal0, $attrVal1) = split(':', $attrVal);
if (!defined $attrVal1) {
if (!defined $attrVal0) {
} elsif ($attrVal0 !~ m/^[+]?\d+$/ || $attrVal0 + 0 > 3600) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
}
} elsif ($attrVal1 !~ m/^[+]?\d+$/ || $attrVal1 + 0 > 3600) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
} else {
if (!defined $attrVal0) {
} elsif ($attrVal0 !~ m/^[+]?\d+$/ || $attrVal0 + 0 > 3600) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
}
}
} elsif ($attrName =~ m/^brightness(DayNight|Sunny).*$/) { } elsif ($attrName =~ m/^brightness(DayNight|Sunny).*$/) {
if (!defined $attrVal) { if (!defined $attrVal) {
@ -619,6 +854,39 @@ sub ElsnerWS_Attr(@) {
} }
} }
} }
} elsif ($attrName =~ m/^customCmd(Down|Up)Period$/) {
my $attrValStr = join("|", keys %customCmdPeriod);
if (!defined $attrVal) {
} elsif ($attrVal !~ m/^($attrValStr)$/) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
}
} elsif ($attrName =~ m/^customCmd(Down|Up)Trigger$/) {
my $attrValStr = join("|", keys %customCmdTrigger);
if (defined $attrVal) {
for (split(',', $attrVal)) {
if ($_ !~ m/^($attrValStr)$/) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
last;
}
}
}
} elsif ($attrName eq "signOfLife") {
if (!defined $attrVal) {
} elsif ($attrVal !~ m/^off|on$/) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
}
} elsif ($attrName eq "signOfLifeInterval") {
if (!defined $attrVal) {
} elsif ($attrVal !~ m/^\d+$/ || $attrVal + 0 < 1 || $attrVal + 0 > 15) {
$err = "attribute-value [$attrName] = $attrVal wrong";
CommandDeleteAttr(undef, "$name $attrName");
}
} elsif ($attrName eq "timeEvent") { } elsif ($attrName eq "timeEvent") {
if (!defined $attrVal) { if (!defined $attrVal) {
@ -740,6 +1008,11 @@ sub ElsnerWS_Delete($$) {
<li>Adjustable switching thresholds and delay times</li> <li>Adjustable switching thresholds and delay times</li>
<li>Day/night signal</li> <li>Day/night signal</li>
<li>Display of date, time, sun azimuth, sun elevation, longitude and latitude</li> <li>Display of date, time, sun azimuth, sun elevation, longitude and latitude</li>
<li>Execution of custom alarm commands, see <a href="#ElsnerWS_customCmdAlarmOff">customCmdAlarmOff</a> and
<a href="#ElsnerWS_customCmdAlarmOn">customCmdAlarmOn</a></li>
<li>Execution of custom up and down commands that can be triggered by the readings dayNight, isRaining, isStormy,
isSunny, isSunnyEast, isSunnySouth, isSunnyWest and isWindy, see <a href="#ElsnerWS_customCmdDown">customCmdDown</a> and
<a href="#ElsnerWS_customCmdUp">customCmdUp</a></li>
</ul><br> </ul><br>
<b>Prerequisites</b> <b>Prerequisites</b>
@ -758,7 +1031,7 @@ sub ElsnerWS_Delete($$) {
More information about the sensors, see for example More information about the sensors, see for example
<a href="https://www.elsner-elektronik.de/shop/de/fileuploader/download/download/?d=1&file=custom%2Fupload%2F30145_P033-RS485-GPS_Datenblatt_13Sep18_DBEEA6042.pdf">P03/3-RS485-GPS User Guide</a>.<br> <a href="https://www.elsner-elektronik.de/shop/de/fileuploader/download/download/?d=1&file=custom%2Fupload%2F30145_P033-RS485-GPS_Datenblatt_13Sep18_DBEEA6042.pdf">P03/3-RS485-GPS User Guide</a>.<br>
The USB adapters The USB adapters
<a href="https://www.digitus.info/produkte/computer-zubehoer-und-komponenten/computer-zubehoer/seriell-und-parallel-adapter/da-70157/">Digitus DA-70157</a>, <a href="https://www.digitus.info/produkte/computer-und-office-zubehoer/computer-zubehoer/usb-komponenten-und-zubehoer/schnittstellen-adapter/da-70157/">Digitus DA-70157</a>,
<a href="https://shop.in-circuit.de/product_info.php?cPath=33&products_id=81">In-Circuit USB-RS485-Bridge</a> <a href="https://shop.in-circuit.de/product_info.php?cPath=33&products_id=81">In-Circuit USB-RS485-Bridge</a>
and <a href="http://www.dsdtech-global.com/2018/01/sh-u10-spp.html">DSD TECH SH-U10 USB to RS485 converter</a> and <a href="http://www.dsdtech-global.com/2018/01/sh-u10-spp.html">DSD TECH SH-U10 USB to RS485 converter</a>
are successfully tested at a Raspberry PI in conjunction with the weather sensor. are successfully tested at a Raspberry PI in conjunction with the weather sensor.
@ -793,7 +1066,7 @@ sub ElsnerWS_Delete($$) {
Control the dayNight reading through the device-specific or custom threshold and delay. Control the dayNight reading through the device-specific or custom threshold and delay.
</li> </li>
<li><a name="ElsnerWS_brightnessDayNightDelay">brightnessDayNightDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_brightnessDayNightDelay">brightnessDayNightDelay</a> t_reset/s:t_set/s,
[brightnessDayNightDelay] = 0...99000:0...99000, 600:600 is default.<br> [brightnessDayNightDelay] = 0...3600:0...3600, 600:600 is default.<br>
Set switching delay for reading dayNight based on the reading brightness. The reading dayNight is reset or set Set switching delay for reading dayNight based on the reading brightness. The reading dayNight is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
@ -802,7 +1075,7 @@ sub ElsnerWS_Delete($$) {
Set switching thresholds for reading isSunny based on the reading brightness. Set switching thresholds for reading isSunny based on the reading brightness.
</li> </li>
<li><a name="ElsnerWS_brightnessSunnyDelay">brightnessSunnyDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_brightnessSunnyDelay">brightnessSunnyDelay</a> t_reset/s:t_set/s,
[brightnessSunnyDelay] = 0...99000:0...99000, 120:30 is default.<br> [brightnessSunnyDelay] = 0...3600:0...3600, 120:30 is default.<br>
Set switching delay for reading isSunny based on the reading brightness. The reading isSunny is reset or set Set switching delay for reading isSunny based on the reading brightness. The reading isSunny is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
@ -811,7 +1084,7 @@ sub ElsnerWS_Delete($$) {
Set switching thresholds for reading isSunnyEast based on the reading sunEast. Set switching thresholds for reading isSunnyEast based on the reading sunEast.
</li> </li>
<li><a name="ElsnerWS_brightnessSunnyEastDelay">brightnessSunnyEastDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_brightnessSunnyEastDelay">brightnessSunnyEastDelay</a> t_reset/s:t_set/s,
[brightnessSunnyDelay] = 0...99000:0...99000, 120:30 is default.<br> [brightnessSunnyDelay] = 0...3600:0...3600, 120:30 is default.<br>
Set switching delay for reading isSunnyEast based on the reading sunEast. The reading isSunnyEast is reset or set Set switching delay for reading isSunnyEast based on the reading sunEast. The reading isSunnyEast is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
@ -820,7 +1093,7 @@ sub ElsnerWS_Delete($$) {
Set switching thresholds for reading isSunnySouth based on the reading sunSouth. Set switching thresholds for reading isSunnySouth based on the reading sunSouth.
</li> </li>
<li><a name="ElsnerWS_brightnessSunnySouthDelay">brightnessSunnySouthDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_brightnessSunnySouthDelay">brightnessSunnySouthDelay</a> t_reset/s:t_set/s,
[brightnessSunnyDelay] = 0...99000:0...99000, 120:30 is default.<br> [brightnessSunnyDelay] = 0...3600:0...3600, 120:30 is default.<br>
Set switching delay for reading isSunnySouth based on the reading sunSouth. The reading isSunnySouth is reset or set Set switching delay for reading isSunnySouth based on the reading sunSouth. The reading isSunnySouth is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
@ -829,37 +1102,111 @@ sub ElsnerWS_Delete($$) {
Set switching thresholds for reading isSunnyWest based on the reading sunWest. Set switching thresholds for reading isSunnyWest based on the reading sunWest.
</li> </li>
<li><a name="ElsnerWS_brightnessSunnyWestDelay">brightnessSunnyWestDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_brightnessSunnyWestDelay">brightnessSunnyWestDelay</a> t_reset/s:t_set/s,
[brightnessSunnyDelay] = 0...99000:0...99000, 120:30 is default.<br> [brightnessSunnyDelay] = 0...3600:0...3600, 120:30 is default.<br>
Set switching delay for reading isSunnyWest based on the reading sunWest. The reading isSunnyWest is reset or set Set switching delay for reading isSunnyWest based on the reading sunWest. The reading isSunnyWest is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
<li><a name="ElsnerWS_customCmdAlarmOff">customCmdAlarmOff</a> &lt;command&gt;<br>
<a name="ElsnerWS_customCmdAlarmOn">customCmdAlarmOn</a> &lt;command&gt;<br>
Command being executed if an alarm is set (on) or deleted (off). If &lt;command&gt; is enclosed in {},
then it is a perl expression, if it is enclosed in "", then it is a shell command,
else it is a "plain" fhem.pl command (chain). In the &lt;command&gt; you can access the name of the device by using $NAME, $TYPE
and the current readings<br>
$BRIGHTNESS, $DATE, $DAYNIGHT, $HEMISPHERE, $ISRAINING, $ISSTORMY, $ISSUNNY, $ISSUNNYEAST, $ISSUNNYSOUTH",
$ISSUNNYWEST, $ISWINDY, $LATITUDE, $LONGITUDE, $SUNAZIMUTH, $SUNEAST, $SUNELAVATION, $SUNSOUTH, $SUNWEST, $TEMPERATURE, $TIME,
$TIMEZONE, $TWILIGHT, $WEEKDAY, $WINDAVG2MIN, $WINDGUST10MIN, $WINDGUSTCURRNT, $WINDPEAK10MIN, $WINDSPEED, $WINDSTENGTH.<br>
The <a href="#eventMap">eventMap</a> replacements are taken into account. This data
is available as a local variable in perl, as environment variable for shell
scripts, and will be textually replaced for Fhem commands.<br>
The alarm commands have a higher priority than the up and down commands.
</li>
<li><a name="ElsnerWS_customCmdDown">customCmdDown</a> &lt;command&gt;<br>
<a name="ElsnerWS_customCmdUp">customCmdUp</a> &lt;command&gt;<br>
The command is executed if the Up or Down command is triggered, see <a href="#ElsnerWS_customCmdDownTrigger">customCmdDownTrigger</a> or
<a href="#ElsnerWS_customCmdUpTrigger">customCmdUpTrigger</a>. If &lt;command&gt; is enclosed in {},
then it is a perl expression, if it is enclosed in "", then it is a shell command,
else it is a "plain" fhem.pl command (chain). In the &lt;command&gt; you can access the name of the device by using $NAME, $TYPE
and the current readings<br>
$BRIGHTNESS, $DATE, $DAYNIGHT, $HEMISPHERE, $ISRAINING, $ISSTORMY, $ISSUNNY, $ISSUNNYEAST, $ISSUNNYSOUTH",
$ISSUNNYWEST, $ISWINDY, $LATITUDE, $LONGITUDE, $SUNAZIMUTH, $SUNEAST, $SUNELAVATION, $SUNSOUTH, $SUNWEST, $TEMPERATURE, $TIME,
$TIMEZONE, $TWILIGHT, $WEEKDAY, $WINDAVG2MIN, $WINDGUST10MIN, $WINDGUSTCURRNT, $WINDPEAK10MIN, $WINDSPEED, $WINDSTENGTH.<br>
The <a href="#eventMap">eventMap</a> replacements are taken into account. This data
is available as a local variable in perl, as environment variable for shell
scripts, and will be textually replaced for Fhem commands.<br>
The alarm commands have a higher priority than the up and down commands.
</li>
<li><a name="ElsnerWS_customCmdDownPeriod">customCmdDownPeriod</a> once|threeTimes|3|10|180|600<br>
<a name="ElsnerWS_customCmdUpPeriod">customCmdUpPeriod</a> once|threeTimes|3|10|180|600<br>
[customCmdDownPeriod] = once|threeTimes|3|10|180|600, once is default.<br>
Number or period of custom command to be executed.
</li>
<li><a name="ElsnerWS_customCmdDownTrigger">customCmdDownTrigger</a> dayNight|isRaining|isStormy|isSunny|isSunnyEast|isSunnySouth|isSunnyWest|isWindy<br>
The commands in the attribute <a href="#ElsnerWS_customCmdDown">customCmdDown</a> are executed if one of the selected readings is triggered as follows:
<ul>
<li>[dayNight] = night</li>
<li>[isRaining] = no</li>
<li>[isStormy] = no</li>
<li>[isSunny] = yes</li>
<li>[isSunnyEast] = yes</li>
<li>[isSunnySouth] = yes</li>
<li>[isSunnyWest] = yes</li>
<li>[isWindy] = no</li>
</ul>
The commands in the attribute <a href="#ElsnerWS_customCmdDown">customCmdDown</a> are executed periodically every second if the attribute is not set.
</li>
<li><a name="ElsnerWS_customCmdUpTrigger">customCmdUpTrigger</a> dayNight|isRaining|isStormy|isSunny|isSunnyEast|isSunnySouth|isSunnyWest|isWindy<br>
The commands in the attribute <a href="#ElsnerWS_customCmdUp">customCmdUp</a> are executed if one of the selected readings is triggered as follows:
<ul>
<li>[dayNight] = day</li>
<li>[isRaining] = yes</li>
<li>[isStormy] = yes</li>
<li>[isSunny] = no</li>
<li>[isSunnyEast] = no</li>
<li>[isSunnySouth] = no</li>
<li>[isSunnyWest] = no</li>
<li>[isWindy] = yes</li>
</ul>
The commands in the attribute <a href="#ElsnerWS_customCmdUp">customCmdUp</a> are executed periodically every second if the attribute is not set.
</li>
<li><a name="ElsnerWS_customCmdPriority">customCmdPriority</a> down|up,
[customCmdPriority] = down|up, up is default.<br>
Priority of custom commands. If both the up and down command are triggered, only the prioritized command is executed.
</li>
<li><a href="#readingFnAttributes">readingFnAttributes</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
<li><a name="ElsnerWS_signOfLife">signOfLife</a> off|on<br>
[signOfLife] = off|on, on is default.<br>
Monitoring of the periodic telegrams from sensor.
</li>
<li><a name="ElsnerWS_signOfLifeInterval">signOfLifeInterval</a> 1...15<br>
[signOfLifeInterval] = 1 ... 15 1/s, 3 is default.<br>
Monitoring period in seconds of the periodic telegrams from sensor.
</li>
<li><a name="ElsnerWS_timeEvent">timeEvent</a> no|yes, <li><a name="ElsnerWS_timeEvent">timeEvent</a> no|yes,
[timeEvent] = no|yes, no is default.<br> [timeEvent] = no|yes, no is default.<br>
Update the reading time periodically. Update the reading time periodically.
</li> </li>
<li><a name="ElsnerWS_updateGlobalAttr">updateGlobalAttr</a> no|yes,
[timeEvent] = no|yes, no is default.<br>
Update the global attributes latitude and longitude with the received GPS coordinates.
</li>
<li><a name="ElsnerWS_windSpeedStormy">windSpeedStormy</a> v_min/m/s:v_max/m/s, <li><a name="ElsnerWS_windSpeedStormy">windSpeedStormy</a> v_min/m/s:v_max/m/s,
[windSpeedStormy] = 0...35:0...35, 13.9:17.2 is default.<br> [windSpeedStormy] = 0...35:0...35, 13.9:17.2 (windStrength = 7 B - 8 B) is default.<br>
Set switching thresholds for reading isStormy based on the reading windSpeed. Set switching thresholds for reading isStormy based on the reading windSpeed.
</li> </li>
<li><a name="ElsnerWS_windSpeedStormyDelay">windSpeedStormyDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_windSpeedStormyDelay">windSpeedStormyDelay</a> t_reset/s:t_set/s,
[windSpeedStormyDelay] = 0...99000:0...99000, 60:3 is default.<br> [windSpeedStormyDelay] = 0...3600:0...3600, 60:3 is default.<br>
Set switching delay for reading isStormy based on the reading windSpeed. The reading isStormy is reset or set Set switching delay for reading isStormy based on the reading windSpeed. The reading isStormy is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
<li><a name="ElsnerWS_windSpeedWindy">windSpeedWindy</a> v_min/m/s:v_max/m/s, <li><a name="ElsnerWS_windSpeedWindy">windSpeedWindy</a> v_min/m/s:v_max/m/s,
[windSpeedWindy] = 0...35:0...35, 1.6:3.4 is default.<br> [windSpeedWindy] = 0...35:0...35, 1.6:3.4 (windStrength = 2 B - 3 B) is default.<br>
Set switching thresholds for reading isWindy based on the reading windSpeed. Set switching thresholds for reading isWindy based on the reading windSpeed.
</li> </li>
<li><a name="ElsnerWS_windSpeedWindyDelay">windSpeedWindyDelay</a> t_reset/s:t_set/s, <li><a name="ElsnerWS_windSpeedWindyDelay">windSpeedWindyDelay</a> t_reset/s:t_set/s,
[windSpeedWindyDelay] = 0...99000:0...99000, 60:3 is default.<br> [windSpeedWindyDelay] = 0...3600:0...3600, 60:3 is default.<br>
Set switching delay for reading isWindy based on the reading windSpeed. The reading isWindy is reset or set Set switching delay for reading isWindy based on the reading windSpeed. The reading isWindy is reset or set
if the thresholds are permanently undershot or exceed during the delay time. if the thresholds are permanently undershot or exceed during the delay time.
</li> </li>
<li><a name="ElsnerWS_updateGlobalAttr">updateGlobalAttr</a> no|yes,
[timeEvent] = no|yes, no is default.<br>
Update the global attributes latitude and longitude with the received GPS coordinates.
</li>
</ul> </ul>
</ul><br> </ul><br>
@ -868,6 +1215,7 @@ sub ElsnerWS_Delete($$) {
<ul> <ul>
<ul> <ul>
<li>T: t/&#176C B: E/lx W: v/m/s IR: no|yes</li> <li>T: t/&#176C B: E/lx W: v/m/s IR: no|yes</li>
<li>alarm: dead_sensor</li>
<li>brightness: E/lx (Sensor Range: E = 0 lx ... 99000 lx)</li> <li>brightness: E/lx (Sensor Range: E = 0 lx ... 99000 lx)</li>
<li>date: JJJJ-MM-TT</li> <li>date: JJJJ-MM-TT</li>
<li>dayNight: day|night</li> <li>dayNight: day|night</li>
@ -892,8 +1240,8 @@ sub ElsnerWS_Delete($$) {
<li>weekday: Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday</li> <li>weekday: Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday</li>
<li>twilight: T/% (Sensor Range: T = 0 % ... 100 %)</li> <li>twilight: T/% (Sensor Range: T = 0 % ... 100 %)</li>
<li>windAvg2min: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li> <li>windAvg2min: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li>
<li>windGustCurrent: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li>
<li>windGust10min: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li> <li>windGust10min: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li>
<li>windGustCurrent: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li>
<li>windPeak10min: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li> <li>windPeak10min: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li>
<li>windSpeed: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li> <li>windSpeed: v/m/s (Sensor Range: v = 0 m/s ... 70 m/s)</li>
<li>windStrength: B (Sensor Range: B = 0 Beaufort ... 12 Beaufort)</li> <li>windStrength: B (Sensor Range: B = 0 Beaufort ... 12 Beaufort)</li>