mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 18:59:33 +00:00
df94cdeb48
git-svn-id: https://svn.fhem.de/fhem/trunk@21846 2b470e98-0d58-463d-a4d8-8e2adae1ed80
2213 lines
95 KiB
Perl
2213 lines
95 KiB
Perl
########################################################################################################################
|
|
# $Id: $
|
|
#########################################################################################################################
|
|
# 60_Watches.pm
|
|
#
|
|
# (c) 2018-2020 by Heiko Maaz
|
|
# e-mail: Heiko dot Maaz at t-online dot de
|
|
#
|
|
# This script is part of fhem.
|
|
#
|
|
# Fhem is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Fhem is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# The script is based on sources from following sites:
|
|
# # modern clock: https://www.w3schools.com/graphics/canvas_clock_start.asp
|
|
# # station clock: http://www.3quarks.com/de/Bahnhofsuhr/
|
|
# # digital clock: http://www.3quarks.com/de/Segmentanzeige/index.html
|
|
#
|
|
#########################################################################################################################
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Time::HiRes qw(time gettimeofday tv_interval);
|
|
|
|
# Versions History intern
|
|
my %Watches_vNotesIntern = (
|
|
"0.12.0" => "03.05.2020 set resume for stopwatch, new 'alarmHMSdel' command for stop watches, alarmHMS renamed to 'alarmHMSdelset' ",
|
|
"0.11.0" => "02.05.2020 alarm event stabilized, reset command for 'countdownwatch', event alarmed contains alarm time ",
|
|
"0.10.0" => "02.05.2020 renamed 'countDownDone' to 'alarmed', bug fix ",
|
|
"0.9.0" => "02.05.2020 new attribute 'timeSource' for selection of client/server time ",
|
|
"0.8.0" => "01.05.2020 new values 'countdownwatch' for attribute digitalDisplayPattern, switch all watches to server time ",
|
|
"0.7.0" => "30.04.2020 new set 'continue' for stopwatch ",
|
|
"0.6.0" => "29.04.2020 new set 'reset' for stopwatch, read 'state' and 'starttime' from readings, add csrf token support ",
|
|
"0.5.0" => "28.04.2020 new values 'stopwatch', 'staticwatch' for attribute digitalDisplayPattern ",
|
|
"0.4.0" => "20.11.2018 text display ",
|
|
"0.3.0" => "19.11.2018 digital clock added ",
|
|
"0.2.0" => "14.11.2018 station clock added ",
|
|
"0.1.0" => "13.11.2018 initial Version with modern analog clock"
|
|
);
|
|
|
|
################################################################
|
|
sub Watches_Initialize {
|
|
my ($hash) = @_;
|
|
|
|
$hash->{DefFn} = "Watches_Define";
|
|
$hash->{SetFn} = "Watches_Set";
|
|
$hash->{AttrList} = "digitalColorBackground:colorpicker ".
|
|
"digitalColorDigits:colorpicker ".
|
|
"digitalDisplayPattern:countdownwatch,staticwatch,stopwatch,text,watch ".
|
|
"digitalDisplayText ".
|
|
"disable:1,0 ".
|
|
"hideDisplayName:1,0 ".
|
|
"htmlattr ".
|
|
"modernColorBackground:colorpicker ".
|
|
"modernColorHand:colorpicker ".
|
|
"modernColorFigure:colorpicker ".
|
|
"modernColorFace:colorpicker ".
|
|
"modernColorRing:colorpicker ".
|
|
"modernColorRingEdge:colorpicker ".
|
|
"stationSecondHand:Bar,HoleShaped,NewHoleShaped,No ".
|
|
"stationSecondHandBehavoir:Bouncing,Overhasty,Creeping,ElasticBouncing ".
|
|
"stationMinuteHandBehavoir:Bouncing,Creeping,ElasticBouncing ".
|
|
"stationBoss:Red,Black,Vienna,No ".
|
|
"stationMinuteHand:Bar,Pointed,Swiss,Vienna ".
|
|
"stationHourHand:Bar,Pointed,Swiss,Vienna ".
|
|
"stationStrokeDial:GermanHour,German,Austria,Swiss,Vienna,No ".
|
|
"stationBody:Round,SmallWhite,RoundGreen,Square,Vienna,No ".
|
|
"timeSource:client,server ".
|
|
"";
|
|
$hash->{FW_summaryFn} = "Watches_FwFn";
|
|
$hash->{FW_detailFn} = "Watches_FwFn";
|
|
$hash->{AttrFn} = "Watches_Attr";
|
|
$hash->{FW_hideDisplayName} = 1; # Forum 88667
|
|
# $hash->{FW_addDetailToSummary} = 1;
|
|
$hash->{FW_atPageEnd} = 1; # wenn 1 -> kein Longpoll ohne informid in HTML-Tag
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
################################################################
|
|
sub Watches_Define {
|
|
my ($hash, $def) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
my @a = split m{\s+}, $def;
|
|
|
|
if(!$a[2]) {
|
|
return "You need to specify more parameters.\n". "Format: define <name> Watches [Modern | Station | Digital]";
|
|
}
|
|
|
|
$hash->{MODEL} = $a[2];
|
|
$hash->{VERSION} = $hash->{VERSION} = (reverse sort(keys %Watches_vNotesIntern))[0];
|
|
|
|
readingsSingleUpdate($hash,"state", "initialized", 1); # Init für "state"
|
|
|
|
return;
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_Set { ## no critic 'complexity'
|
|
my ($hash, @a) = @_;
|
|
return "\"set X\" needs at least an argument" if ( @a < 2 );
|
|
my $name = $a[0];
|
|
my $opt = $a[1];
|
|
my $prop = $a[2];
|
|
my $prop1 = $a[3];
|
|
my $prop2 = $a[4];
|
|
my $prop3 = $a[5];
|
|
my $model = $hash->{MODEL};
|
|
my $addp = AttrVal($name,"digitalDisplayPattern","watch");
|
|
|
|
return if(IsDisabled($name) || $addp !~ /stopwatch|staticwatch|countdownwatch/);
|
|
|
|
my $setlist = "Unknown argument $opt, choose one of ";
|
|
$setlist .= "time " if($addp =~ /staticwatch/);
|
|
$setlist .= "alarmHMSset alarmHMSdel:noArg reset:noArg start:noArg stop:noArg " if($addp =~ /stopwatch|countdownwatch/);
|
|
$setlist .= "resume:noArg " if($addp =~ /stopwatch/);
|
|
$setlist .= "countDownInit continue:noArg" if($addp =~ /countdownwatch/);
|
|
|
|
if ($opt =~ /\bstart\b/) {
|
|
return qq{Please set "countDownInit" before !} if($addp =~ /countdownwatch/ && !ReadingsVal($name, "countInitVal", ""));
|
|
|
|
my $ms = int(time*1000);
|
|
|
|
readingsBeginUpdate ($hash);
|
|
readingsBulkUpdate ($hash, "alarmed", 0) if($addp =~ /stopwatch|countdownwatch/);
|
|
readingsBulkUpdate ($hash, "starttime", $ms);
|
|
readingsBulkUpdate ($hash, "state", "started");
|
|
readingsEndUpdate ($hash, 1);
|
|
|
|
} elsif ($opt eq "alarmHMSset") {
|
|
$prop = ($prop ne "") ? $prop : 70; # Stunden
|
|
$prop1 = ($prop1 ne "") ? $prop1 : 70; # Minuten
|
|
$prop2 = ($prop2 ne "") ? $prop2 : 70; # Sekunden
|
|
return qq{The value for "$opt" is invalid. Use parameter "hh mm ss" like "19 45 13".} if($prop>24 || $prop1>59 || $prop2>59);
|
|
|
|
my $at = sprintf("%02d",$prop).":".sprintf("%02d",$prop1).":".sprintf("%02d",$prop2);
|
|
|
|
Watches_delread ($name, "alarmTime");
|
|
|
|
readingsBeginUpdate ($hash);
|
|
readingsBulkUpdate ($hash, "alarmed", 0);
|
|
readingsBulkUpdate ($hash, "alarmTime", $at);
|
|
readingsEndUpdate ($hash, 1);
|
|
|
|
} elsif ($opt eq "alarmHMSdel") {
|
|
Watches_delread ($name, "alarmTime");
|
|
Watches_delread ($name, "alarmed");
|
|
|
|
} elsif ($opt eq "countDownInit") {
|
|
$prop = ($prop ne "") ? $prop : 70; # Stunden
|
|
$prop1 = ($prop1 ne "") ? $prop1 : 70; # Minuten
|
|
$prop2 = ($prop2 ne "") ? $prop2 : 70; # Sekunden
|
|
return qq{The value for "$opt" is invalid. Use parameter "hh mm ss" like "19 45 13".} if($prop>24 || $prop1>59 || $prop2>59);
|
|
|
|
my $st = int(time*1000); # Millisekunden !
|
|
my $ct = $prop*3600 + $prop1*60 + $prop2; # Sekunden !
|
|
|
|
Watches_delread ($name, "countInitVal");
|
|
|
|
readingsBeginUpdate ($hash);
|
|
readingsBulkUpdate ($hash, "countInitVal", $ct);
|
|
readingsBulkUpdate ($hash, "state", "initialized");
|
|
readingsEndUpdate ($hash, 1);
|
|
|
|
} elsif ($opt eq "continue") {
|
|
return qq{Please set "countDownInit" before !} if($addp =~ /countdownwatch/ && !ReadingsVal($name, "countInitVal", ""));
|
|
|
|
if(!ReadingsVal($name, "starttime", "")) {
|
|
my $ms = int(time*1000);
|
|
readingsSingleUpdate($hash, "starttime", $ms, 0);
|
|
}
|
|
return if(ReadingsVal($name, "state", "") eq "started");
|
|
readingsSingleUpdate($hash, "state", "started", 1);
|
|
|
|
} elsif ($opt eq "resume") {
|
|
return qq{Please set "countDownInit" before !} if($addp =~ /countdownwatch/ && !ReadingsVal($name, "countInitVal", ""));
|
|
|
|
my $ms = int(time*1000);
|
|
readingsSingleUpdate($hash, "starttime", $ms, 0);
|
|
|
|
return if(ReadingsVal($name, "state", "") eq "started");
|
|
readingsSingleUpdate($hash, "state", "resumed", 1);
|
|
|
|
} elsif ($opt eq "stop") {
|
|
readingsSingleUpdate($hash, "state", "stopped", 1);
|
|
|
|
} elsif ($opt eq "reset") {
|
|
Watches_delread ($name);
|
|
readingsSingleUpdate($hash, "state", "initialized", 1);
|
|
|
|
} elsif ($opt eq "time") {
|
|
return qq{The value for "$opt" is invalid. Use parameter "hh mm ss" like "19 45 13".} if($prop>24 || $prop1>59 || $prop2>59);
|
|
|
|
readingsBeginUpdate ($hash);
|
|
readingsBulkUpdateIfChanged ($hash, "hour", $prop);
|
|
readingsBulkUpdateIfChanged ($hash, "minute", $prop1);
|
|
readingsBulkUpdate ($hash, "second", $prop2);
|
|
readingsEndUpdate ($hash, 1);
|
|
|
|
} else {
|
|
return "$setlist";
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_Attr {
|
|
my ($cmd,$name,$aName,$aVal) = @_;
|
|
my $hash = $defs{$name};
|
|
my ($do,$val);
|
|
|
|
# $cmd can be "del" or "set"
|
|
# $name is device name
|
|
# aName and aVal are Attribute name and value
|
|
|
|
if ($cmd eq "set" && $hash->{MODEL} !~ /modern/i && $aName =~ /^modern.*/) {
|
|
return qq{"$aName" is only valid for Watches model "Modern"};
|
|
}
|
|
|
|
if ($cmd eq "set" && $hash->{MODEL} !~ /station/i && $aName =~ /^station.*/) {
|
|
return qq{"$aName" is only valid for Watches model "Station"};
|
|
}
|
|
|
|
if ($cmd eq "set" && $hash->{MODEL} !~ /digital/i && $aName =~ /^digital.*/) {
|
|
return qq{"$aName" is only valid for Watches model "Digital"};
|
|
}
|
|
|
|
if ($aName eq "disable") {
|
|
if($cmd eq "set") {
|
|
$do = ($aVal) ? 1 : 0;
|
|
}
|
|
$do = 0 if($cmd eq "del");
|
|
$val = ($do == 1 ? "disabled" : "initialized");
|
|
|
|
readingsSingleUpdate($hash, "state", $val, 1);
|
|
}
|
|
|
|
if ($aName eq "digitalDisplayPattern") {
|
|
if($cmd eq "set") {
|
|
$do = $aVal;
|
|
}
|
|
$do = 0 if($cmd eq "del");
|
|
|
|
Watches_delread ($name);
|
|
|
|
readingsSingleUpdate($hash, "state", "initialized", 1);
|
|
|
|
if($do =~ /\bstopwatch\b/) {
|
|
my $ms = int(time*1000);
|
|
readingsSingleUpdate($hash, "starttime", $ms, 0);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_FwFn {
|
|
my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
|
|
my $hash = $defs{$d};
|
|
|
|
my $alias = AttrVal($d, "alias", $d); # Linktext als Aliasname oder Devicename setzen
|
|
my $dlink = "<a href=\"/fhem?detail=$d\">$alias</a>";
|
|
|
|
my $ret = "";
|
|
$ret .= "<span>$dlink </span><br>" if(!AttrVal($d,"hideDisplayName",0));
|
|
if(IsDisabled($d)) {
|
|
if(AttrVal($d,"hideDisplayName",0)) {
|
|
$ret .= "Watch <a href=\"/fhem?detail=$d\">$d</a> is disabled";
|
|
} else {
|
|
$ret .= "<html>Watch is disabled</html>";
|
|
}
|
|
} else {
|
|
$ret .= Watches_modern($d) if($hash->{MODEL} =~ /modern/i);
|
|
$ret .= Watches_station($d) if($hash->{MODEL} =~ /station/i);
|
|
$ret .= Watches_digital($d) if($hash->{MODEL} =~ /digital/i);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_delread {
|
|
my ($name,$reading) = @_;
|
|
my $hash = $defs{$name};
|
|
|
|
if($reading) {
|
|
readingsDelete($hash,$reading);
|
|
return;
|
|
}
|
|
|
|
my @allrds = keys%{$hash->{READINGS}};
|
|
for my $key(@allrds) {
|
|
next if($key =~ /\bstate\b/);
|
|
readingsDelete($hash,$key);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_digital {
|
|
my ($d) = @_;
|
|
my $hash = $defs{$d};
|
|
my $alarmdef = "00:00:00";
|
|
my $hattr = AttrVal($d, "htmlattr", "width='150' height='50'");
|
|
my $bgc = AttrVal($d, "digitalColorBackground", "C4C4C4");
|
|
my $dcd = AttrVal($d, "digitalColorDigits", "000000");
|
|
my $addp = AttrVal($d, "digitalDisplayPattern", "watch");
|
|
my $ddt = AttrVal($d, "digitalDisplayText", "Play");
|
|
my $alarm = " ".ReadingsVal($d, "alarmTime", $alarmdef);
|
|
|
|
my $ddp = "###:##:##"; # dummy
|
|
my ($h,$m,$s) = (0,0,0);
|
|
|
|
if($addp eq "watch") {
|
|
$ddp = "###:##:##";
|
|
$ddt = "((hours < 10) ? ' 0' : ' ') + hours
|
|
+ ':' + ((minutes < 10) ? '0' : '') + minutes
|
|
+ ':' + ((seconds < 10) ? '0' : '') + seconds";
|
|
|
|
} elsif($addp eq "stopwatch" || $addp eq "countdownwatch") {
|
|
$ddp = "###:##:##";
|
|
$ddt = "((hours_$d < 10) ? ' 0' : ' ') + hours_$d
|
|
+ ':' + ((minutes_$d < 10) ? '0' : '') + minutes_$d
|
|
+ ':' + ((seconds_$d < 10) ? '0' : '') + seconds_$d";
|
|
|
|
} elsif($addp eq "staticwatch") {
|
|
$ddp = "###:##:##";
|
|
$h = ReadingsVal($d, "hour" , 0);
|
|
$m = ReadingsVal($d, "minute", 0);
|
|
$s = ReadingsVal($d, "second", 0);
|
|
$ddt = "((hours_$d < 10) ? ' 0' : ' ') + hours_$d
|
|
+ ':' + ((minutes_$d < 10) ? '0' : '') + minutes_$d
|
|
+ ':' + ((seconds_$d < 10) ? '0' : '') + seconds_$d";
|
|
|
|
} elsif($addp eq "text") {
|
|
my $txtc = length($ddt);
|
|
$ddp = "";
|
|
for(my $i = 0; $i <= $txtc; $i++) {
|
|
$ddp .= "#";
|
|
}
|
|
$ddt = "' ".$ddt."'";
|
|
}
|
|
|
|
# Segmentanzeige aus: http://www.3quarks.com/de/Segmentanzeige/index.html
|
|
|
|
return "
|
|
<html>
|
|
<body>
|
|
|
|
<canvas id='display_$d' $hattr style='background-color:#$bgc'></canvas>
|
|
|
|
<script>
|
|
// Segment display types
|
|
SegmentDisplay_$d.SevenSegment = 7;
|
|
SegmentDisplay_$d.FourteenSegment = 14;
|
|
SegmentDisplay_$d.SixteenSegment = 16;
|
|
|
|
// Segment corner types
|
|
SegmentDisplay_$d.SymmetricCorner = 0;
|
|
SegmentDisplay_$d.SquaredCorner = 1;
|
|
SegmentDisplay_$d.RoundedCorner = 2;
|
|
|
|
// Definition variables
|
|
var state_$d;
|
|
var st_$d;
|
|
var ct_$d;
|
|
var ci_$d;
|
|
var csrf;
|
|
var url_$d;
|
|
var devName_$d;
|
|
var selVal_$d;
|
|
var hours_$d;
|
|
var minutes_$d;
|
|
var seconds_$d;
|
|
var startDate_$d;
|
|
var afree_$d = 0;
|
|
|
|
function SegmentDisplay_$d(displayId_$d) {
|
|
this.displayId_$d = displayId_$d;
|
|
this.pattern = '##:##:##';
|
|
this.value = '12:34:56';
|
|
this.digitHeight = 20;
|
|
this.digitWidth = 10;
|
|
this.digitDistance = 2.5;
|
|
this.displayAngle = 12;
|
|
this.segmentWidth = 2.5;
|
|
this.segmentDistance = 0.2;
|
|
this.segmentCount = SegmentDisplay_$d.SevenSegment;
|
|
this.cornerType = SegmentDisplay_$d.RoundedCorner;
|
|
this.colorOn = 'rgb(233, 93, 15)';
|
|
this.colorOff = 'rgb(75, 30, 5)';
|
|
};
|
|
|
|
SegmentDisplay_$d.prototype.setValue = function(value) {
|
|
this.value = value;
|
|
this.draw();
|
|
};
|
|
|
|
SegmentDisplay_$d.prototype.draw = function() {
|
|
var display_$d = document.getElementById(this.displayId_$d);
|
|
if (display_$d) {
|
|
var context = display_$d.getContext('2d');
|
|
if (context) {
|
|
// clear canvas
|
|
context.clearRect(0, 0, display_$d.width, display_$d.height);
|
|
|
|
// compute and check display width
|
|
var width = 0;
|
|
var first = true;
|
|
if (this.pattern) {
|
|
for (var i = 0; i < this.pattern.length; i++) {
|
|
var c = this.pattern.charAt(i).toLowerCase();
|
|
if (c == '#') {
|
|
width += this.digitWidth;
|
|
} else if (c == '.' || c == ':') {
|
|
width += this.segmentWidth;
|
|
} else if (c != ' ') {
|
|
return;
|
|
}
|
|
width += first ? 0 : this.digitDistance;
|
|
first = false;
|
|
}
|
|
}
|
|
if (width <= 0) {
|
|
return;
|
|
}
|
|
|
|
// compute skew factor
|
|
var angle = -1.0 * Math.max(-45.0, Math.min(45.0, this.displayAngle));
|
|
var skew = Math.tan((angle * Math.PI) / 180.0);
|
|
|
|
// compute scale factor
|
|
var scale = Math.min(display_$d.width / (width + Math.abs(skew * this.digitHeight)), display_$d.height / this.digitHeight);
|
|
|
|
// compute display offset
|
|
var offsetX = (display_$d.width - (width + skew * this.digitHeight) * scale) / 2.0;
|
|
var offsetY = (display_$d.height - this.digitHeight * scale) / 2.0;
|
|
|
|
// context transformation
|
|
context.save();
|
|
context.translate(offsetX, offsetY);
|
|
context.scale(scale, scale);
|
|
context.transform(1, 0, skew, 1, 0, 0);
|
|
|
|
// draw segments
|
|
var xPos = 0;
|
|
var size = (this.value) ? this.value.length : 0;
|
|
for (var i = 0; i < this.pattern.length; i++) {
|
|
var mask = this.pattern.charAt(i);
|
|
var value = (i < size) ? this.value.charAt(i).toLowerCase() : ' ';
|
|
xPos += this.drawDigit(context, xPos, mask, value);
|
|
}
|
|
|
|
// finish drawing
|
|
context.restore();
|
|
}
|
|
}
|
|
};
|
|
|
|
SegmentDisplay_$d.prototype.drawDigit = function(context, xPos, mask, c) {
|
|
switch (mask) {
|
|
case '#':
|
|
var r = Math.sqrt(this.segmentWidth * this.segmentWidth / 2.0);
|
|
var d = Math.sqrt(this.segmentDistance * this.segmentDistance / 2.0);
|
|
var e = d / 2.0;
|
|
var f = (this.segmentWidth - d) * Math.sin((45.0 * Math.PI) / 180.0);
|
|
var g = f / 2.0;
|
|
var h = (this.digitHeight - 3.0 * this.segmentWidth) / 2.0;
|
|
var w = (this.digitWidth - 3.0 * this.segmentWidth) / 2.0;
|
|
var s = this.segmentWidth / 2.0;
|
|
var t = this.digitWidth / 2.0;
|
|
|
|
// draw segment a (a1 and a2 for 16 segments)
|
|
if (this.segmentCount == 16) {
|
|
var x = xPos;
|
|
var y = 0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '02356789abcdefgiopqrstz@%');
|
|
context.beginPath();
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.moveTo(x + s + d, y + s);
|
|
context.lineTo(x + this.segmentWidth + d, y);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.moveTo(x + s + e, y + s - e);
|
|
context.lineTo(x + this.segmentWidth, y);
|
|
break;
|
|
default:
|
|
context.moveTo(x + this.segmentWidth - f, y + this.segmentWidth - f - d);
|
|
context.quadraticCurveTo(x + this.segmentWidth - g, y, x + this.segmentWidth, y);
|
|
}
|
|
context.lineTo(x + t - d - s, y);
|
|
context.lineTo(x + t - d, y + s);
|
|
context.lineTo(x + t - d - s, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
|
|
context.fill();
|
|
|
|
var x = xPos;
|
|
var y = 0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '02356789abcdefgiopqrstz\@');
|
|
context.beginPath();
|
|
context.moveTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
|
|
context.lineTo(x + t + d + s, y + this.segmentWidth);
|
|
context.lineTo(x + t + d, y + s);
|
|
context.lineTo(x + t + d + s, y);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
|
|
context.lineTo(x + this.digitWidth - s - d, y + s);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
|
|
context.lineTo(x + this.digitWidth - s - e, y + s - e);
|
|
break;
|
|
default:
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
|
|
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y, x + this.digitWidth - this.segmentWidth + f, y + this.segmentWidth - f - d);
|
|
}
|
|
context.fill();
|
|
|
|
} else {
|
|
var x = xPos;
|
|
var y = 0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '02356789acefp', '02356789abcdefgiopqrstz\@');
|
|
context.beginPath();
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.moveTo(x + s + d, y + s);
|
|
context.lineTo(x + this.segmentWidth + d, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
|
|
context.lineTo(x + this.digitWidth - s - d, y + s);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.moveTo(x + s + e, y + s - e);
|
|
context.lineTo(x + this.segmentWidth, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
|
|
context.lineTo(x + this.digitWidth - s - e, y + s - e);
|
|
break;
|
|
default:
|
|
context.moveTo(x + this.segmentWidth - f, y + this.segmentWidth - f - d);
|
|
context.quadraticCurveTo(x + this.segmentWidth - g, y, x + this.segmentWidth, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth, y);
|
|
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y, x + this.digitWidth - this.segmentWidth + f, y + this.segmentWidth - f - d);
|
|
}
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
|
|
context.fill();
|
|
}
|
|
|
|
// draw segment b
|
|
x = xPos + this.digitWidth - this.segmentWidth;
|
|
y = 0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '01234789adhpy', '01234789abdhjmnopqruwy');
|
|
context.beginPath();
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.moveTo(x + s, y + s + d);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.moveTo(x + s + e, y + s + e);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
|
|
break;
|
|
default:
|
|
context.moveTo(x + f + d, y + this.segmentWidth - f);
|
|
context.quadraticCurveTo(x + this.segmentWidth, y + this.segmentWidth - g, x + this.segmentWidth, y + this.segmentWidth);
|
|
}
|
|
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
|
|
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
context.lineTo(x, y + this.segmentWidth + d);
|
|
context.fill();
|
|
|
|
// draw segment c
|
|
x = xPos + this.digitWidth - this.segmentWidth;
|
|
y = h + this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '013456789abdhnouy', '01346789abdghjmnoqsuw\@', '%');
|
|
context.beginPath();
|
|
context.moveTo(x, y + this.segmentWidth + d);
|
|
context.lineTo(x + s, y + s + d);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
|
|
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x + s + e, y + h + this.segmentWidth + s - e);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
break;
|
|
default:
|
|
context.quadraticCurveTo(x + this.segmentWidth, y + h + this.segmentWidth + g, x + f + d, y + h + this.segmentWidth + f);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
}
|
|
context.fill();
|
|
|
|
// draw segment d (d1 and d2 for 16 segments)
|
|
if (this.segmentCount == 16) {
|
|
x = xPos;
|
|
y = this.digitHeight - this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '0235689bcdegijloqsuz_=\@');
|
|
context.beginPath();
|
|
context.moveTo(x + this.segmentWidth + d, y);
|
|
context.lineTo(x + t - d - s, y);
|
|
context.lineTo(x + t - d, y + s);
|
|
context.lineTo(x + t - d - s, y + this.segmentWidth);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
|
|
context.lineTo(x + s + d, y + s);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
|
|
context.lineTo(x + s + e, y + s + e);
|
|
break;
|
|
default:
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
|
|
context.quadraticCurveTo(x + this.segmentWidth - g, y + this.segmentWidth, x + this.segmentWidth - f, y + f + d);
|
|
context.lineTo(x + this.segmentWidth - f, y + f + d);
|
|
}
|
|
context.fill();
|
|
|
|
x = xPos;
|
|
y = this.digitHeight - this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '0235689bcdegijloqsuz_=\@', '%');
|
|
context.beginPath();
|
|
context.moveTo(x + t + d + s, y + this.segmentWidth);
|
|
context.lineTo(x + t + d, y + s);
|
|
context.lineTo(x + t + d + s, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x + this.digitWidth - s - d, y + s);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x + this.digitWidth - s - e, y + s + e);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
|
|
break;
|
|
default:
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth + f, y + f + d);
|
|
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y + this.segmentWidth, x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
|
|
}
|
|
context.fill();
|
|
|
|
} else {
|
|
x = xPos;
|
|
y = this.digitHeight - this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '0235689bcdelotuy_', '0235689bcdegijloqsuz_=\@');
|
|
context.beginPath();
|
|
context.moveTo(x + this.segmentWidth + d, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x + this.digitWidth - s - d, y + s);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
|
|
context.lineTo(x + s + d, y + s);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x + this.digitWidth - s - e, y + s + e);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
|
|
context.lineTo(x + s + e, y + s + e);
|
|
break;
|
|
default:
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth + f, y + f + d);
|
|
context.quadraticCurveTo(x + this.digitWidth - this.segmentWidth + g, y + this.segmentWidth, x + this.digitWidth - this.segmentWidth, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth);
|
|
context.quadraticCurveTo(x + this.segmentWidth - g, y + this.segmentWidth, x + this.segmentWidth - f, y + f + d);
|
|
context.lineTo(x + this.segmentWidth - f, y + f + d);
|
|
}
|
|
context.fill();
|
|
}
|
|
|
|
// draw segment e
|
|
x = xPos;
|
|
y = h + this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '0268abcdefhlnoprtu', '0268acefghjklmnopqruvw\@');
|
|
context.beginPath();
|
|
context.moveTo(x, y + this.segmentWidth + d);
|
|
context.lineTo(x + s, y + s + d);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
|
|
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x + s - e, y + h + this.segmentWidth + s - d + e);
|
|
context.lineTo(x, y + h + this.segmentWidth);
|
|
break;
|
|
default:
|
|
context.lineTo(x + this.segmentWidth - f - d, y + h + this.segmentWidth + f);
|
|
context.quadraticCurveTo(x, y + h + this.segmentWidth + g, x, y + h + this.segmentWidth);
|
|
}
|
|
context.fill();
|
|
|
|
// draw segment f
|
|
x = xPos;
|
|
y = 0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '045689abcefhlpty', '045689acefghklmnopqrsuvwy\@', '%');
|
|
context.beginPath();
|
|
context.moveTo(x + this.segmentWidth, y + this.segmentWidth + d);
|
|
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
|
|
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
switch (this.cornerType) {
|
|
case SegmentDisplay_$d.SymmetricCorner:
|
|
context.lineTo(x, y + this.segmentWidth + d);
|
|
context.lineTo(x + s, y + s + d);
|
|
break;
|
|
case SegmentDisplay_$d.SquaredCorner:
|
|
context.lineTo(x, y + this.segmentWidth);
|
|
context.lineTo(x + s - e, y + s + e);
|
|
break;
|
|
default:
|
|
context.lineTo(x, y + this.segmentWidth);
|
|
context.quadraticCurveTo(x, y + this.segmentWidth - g, x + this.segmentWidth - f - d, y + this.segmentWidth - f);
|
|
context.lineTo(x + this.segmentWidth - f - d, y + this.segmentWidth - f);
|
|
}
|
|
context.fill();
|
|
|
|
// draw segment g for 7 segments
|
|
if (this.segmentCount == 7) {
|
|
x = xPos;
|
|
y = (this.digitHeight - this.segmentWidth) / 2.0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, '2345689abdefhnoprty-=');
|
|
context.beginPath();
|
|
context.moveTo(x + s + d, y + s);
|
|
context.lineTo(x + this.segmentWidth + d, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
|
|
context.lineTo(x + this.digitWidth - s - d, y + s);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
|
|
context.fill();
|
|
}
|
|
|
|
// draw inner segments for the fourteen- and sixteen-segment-display
|
|
if (this.segmentCount != 7) {
|
|
// draw segment g1
|
|
x = xPos;
|
|
y = (this.digitHeight - this.segmentWidth) / 2.0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '2345689aefhkprsy-+*=', '%');
|
|
context.beginPath();
|
|
context.moveTo(x + s + d, y + s);
|
|
context.lineTo(x + this.segmentWidth + d, y);
|
|
context.lineTo(x + t - d - s, y);
|
|
context.lineTo(x + t - d, y + s);
|
|
context.lineTo(x + t - d - s, y + this.segmentWidth);
|
|
context.lineTo(x + this.segmentWidth + d, y + this.segmentWidth);
|
|
context.fill();
|
|
|
|
// draw segment g2
|
|
x = xPos;
|
|
y = (this.digitHeight - this.segmentWidth) / 2.0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '234689abefghprsy-+*=\@', '%');
|
|
context.beginPath();
|
|
context.moveTo(x + t + d, y + s);
|
|
context.lineTo(x + t + d + s, y);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y);
|
|
context.lineTo(x + this.digitWidth - s - d, y + s);
|
|
context.lineTo(x + this.digitWidth - this.segmentWidth - d, y + this.segmentWidth);
|
|
context.lineTo(x + t + d + s, y + this.segmentWidth);
|
|
context.fill();
|
|
|
|
// draw segment j
|
|
x = xPos + t - s;
|
|
y = 0;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, 'bdit+*', '%');
|
|
context.beginPath();
|
|
if (this.segmentCount == 14) {
|
|
context.moveTo(x, y + this.segmentWidth + this.segmentDistance);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + this.segmentDistance);
|
|
} else {
|
|
context.moveTo(x, y + this.segmentWidth + d);
|
|
context.lineTo(x + s, y + s + d);
|
|
context.lineTo(x + this.segmentWidth, y + this.segmentWidth + d);
|
|
}
|
|
context.lineTo(x + this.segmentWidth, y + h + this.segmentWidth - d);
|
|
context.lineTo(x + s, y + h + this.segmentWidth + s - d);
|
|
context.lineTo(x, y + h + this.segmentWidth - d);
|
|
context.fill();
|
|
|
|
// draw segment m
|
|
x = xPos + t - s;
|
|
y = this.digitHeight;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, 'bdity+*\@', '%');
|
|
context.beginPath();
|
|
if (this.segmentCount == 14) {
|
|
context.moveTo(x, y - this.segmentWidth - this.segmentDistance);
|
|
context.lineTo(x + this.segmentWidth, y - this.segmentWidth - this.segmentDistance);
|
|
} else {
|
|
context.moveTo(x, y - this.segmentWidth - d);
|
|
context.lineTo(x + s, y - s - d);
|
|
context.lineTo(x + this.segmentWidth, y - this.segmentWidth - d);
|
|
}
|
|
context.lineTo(x + this.segmentWidth, y - h - this.segmentWidth + d);
|
|
context.lineTo(x + s, y - h - this.segmentWidth - s + d);
|
|
context.lineTo(x, y - h - this.segmentWidth + d);
|
|
context.fill();
|
|
|
|
// draw segment h
|
|
x = xPos + this.segmentWidth;
|
|
y = this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, 'mnx\\\\*');
|
|
context.beginPath();
|
|
context.moveTo(x + this.segmentDistance, y + this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance + r, y + this.segmentDistance);
|
|
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance - r);
|
|
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance);
|
|
context.lineTo(x + w - this.segmentDistance - r , y + h - this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance, y + this.segmentDistance + r);
|
|
context.fill();
|
|
|
|
// draw segment k
|
|
x = xPos + w + 2.0 * this.segmentWidth;
|
|
y = this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '0kmvxz/*', '%');
|
|
context.beginPath();
|
|
context.moveTo(x + w - this.segmentDistance, y + this.segmentDistance);
|
|
context.lineTo(x + w - this.segmentDistance, y + this.segmentDistance + r);
|
|
context.lineTo(x + this.segmentDistance + r, y + h - this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance - r);
|
|
context.lineTo(x + w - this.segmentDistance - r, y + this.segmentDistance);
|
|
context.fill();
|
|
|
|
// draw segment l
|
|
x = xPos + w + 2.0 * this.segmentWidth;
|
|
y = h + 2.0 * this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '5knqrwx\\\\*');
|
|
context.beginPath();
|
|
context.moveTo(x + this.segmentDistance, y + this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance + r, y + this.segmentDistance);
|
|
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance - r);
|
|
context.lineTo(x + w - this.segmentDistance , y + h - this.segmentDistance);
|
|
context.lineTo(x + w - this.segmentDistance - r , y + h - this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance, y + this.segmentDistance + r);
|
|
context.fill();
|
|
|
|
// draw segment n
|
|
x = xPos + this.segmentWidth;
|
|
y = h + 2.0 * this.segmentWidth;
|
|
context.fillStyle = this.getSegmentColor_$d(c, null, '0vwxz/*', '%');
|
|
context.beginPath();
|
|
context.moveTo(x + w - this.segmentDistance, y + this.segmentDistance);
|
|
context.lineTo(x + w - this.segmentDistance, y + this.segmentDistance + r);
|
|
context.lineTo(x + this.segmentDistance + r, y + h - this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance);
|
|
context.lineTo(x + this.segmentDistance, y + h - this.segmentDistance - r);
|
|
context.lineTo(x + w - this.segmentDistance - r, y + this.segmentDistance);
|
|
context.fill();
|
|
}
|
|
|
|
return this.digitDistance + this.digitWidth;
|
|
|
|
case '.':
|
|
context.fillStyle = (c == '#') || (c == '.') ? this.colorOn : this.colorOff;
|
|
this.drawPoint(context, xPos, this.digitHeight - this.segmentWidth, this.segmentWidth);
|
|
return this.digitDistance + this.segmentWidth;
|
|
|
|
case ':':
|
|
context.fillStyle = (c == '#') || (c == ':') ? this.colorOn : this.colorOff;
|
|
var y = (this.digitHeight - this.segmentWidth) / 2.0 - this.segmentWidth;
|
|
this.drawPoint(context, xPos, y, this.segmentWidth);
|
|
this.drawPoint(context, xPos, y + 2.0 * this.segmentWidth, this.segmentWidth);
|
|
return this.digitDistance + this.segmentWidth;
|
|
|
|
default:
|
|
return this.digitDistance;
|
|
}
|
|
};
|
|
|
|
SegmentDisplay_$d.prototype.drawPoint = function(context, x1, y1, size) {
|
|
var x2 = x1 + size;
|
|
var y2 = y1 + size;
|
|
var d = size / 4.0;
|
|
|
|
context.beginPath();
|
|
context.moveTo(x2 - d, y1);
|
|
context.quadraticCurveTo(x2, y1, x2, y1 + d);
|
|
context.lineTo(x2, y2 - d);
|
|
context.quadraticCurveTo(x2, y2, x2 - d, y2);
|
|
context.lineTo(x1 + d, y2);
|
|
context.quadraticCurveTo(x1, y2, x1, y2 - d);
|
|
context.lineTo(x1, y1 + d);
|
|
context.quadraticCurveTo(x1, y1, x1 + d, y1);
|
|
context.fill();
|
|
};
|
|
|
|
SegmentDisplay_$d.prototype.getSegmentColor_$d = function(c, charSet7, charSet14, charSet16) {
|
|
if (c == '#') {
|
|
return this.colorOn;
|
|
} else {
|
|
switch (this.segmentCount) {
|
|
case 7: return (charSet7.indexOf(c) == -1) ? this.colorOff : this.colorOn;
|
|
case 14: return (charSet14.indexOf(c) == -1) ? this.colorOff : this.colorOn;
|
|
case 16: var pattern = charSet14 + (charSet16 === undefined ? '' : charSet16);
|
|
return (pattern.indexOf(c) == -1) ? this.colorOff : this.colorOn;
|
|
default: return this.colorOff;
|
|
}
|
|
}
|
|
};
|
|
|
|
var display_$d = new SegmentDisplay_$d('display_$d');
|
|
display_$d.pattern = '$ddp ';
|
|
display_$d.cornerType = 2;
|
|
display_$d.displayType = 7;
|
|
display_$d.displayAngle = 9;
|
|
display_$d.digitHeight = 20;
|
|
display_$d.digitWidth = 12;
|
|
display_$d.digitDistance = 2;
|
|
display_$d.segmentWidth = 3;
|
|
display_$d.segmentDistance = 0.5;
|
|
//display_$d.colorOn = 'rgba(0, 0, 0, 0.9)';
|
|
display_$d.colorOn = '#$dcd';
|
|
display_$d.colorOff = 'rgba(0, 0, 0, 0.1)';
|
|
|
|
// CSRF-Token auslesen
|
|
var body = document.querySelector(\"body\");
|
|
if( body != null ) {
|
|
csrf = body.getAttribute(\"fwcsrf\");
|
|
}
|
|
|
|
// get the base url
|
|
function getBaseUrl () {
|
|
var url = window.location.href.split(\"?\")[0];
|
|
url += \"?\";
|
|
if( csrf != null ) {
|
|
url += \"fwcsrf=\"+csrf+\"&\";
|
|
}
|
|
return url;
|
|
}
|
|
|
|
function makeCommand (cmd) {
|
|
return getBaseUrl()+\"cmd=\"+encodeURIComponent(cmd)+\"&XHR=1\";
|
|
}
|
|
|
|
// localStorage Set
|
|
function localStoreSet (hours, minutes, seconds, sumsecs) {
|
|
if (Number.isInteger(hours)) { localStorage.setItem('h_$d', hours); }
|
|
if (Number.isInteger(minutes)) { localStorage.setItem('m_$d', minutes); }
|
|
if (Number.isInteger(seconds)) { localStorage.setItem('s_$d', seconds); }
|
|
if (Number.isInteger(sumsecs)) { localStorage.setItem('ss_$d', sumsecs); }
|
|
}
|
|
|
|
animate_$d();
|
|
|
|
function animate_$d() {
|
|
var watchkind_$d = '$addp';
|
|
|
|
if (watchkind_$d == 'watch') {
|
|
// aktueller Timestamp in Millisekunden
|
|
command = '{ int(time*1000) }';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {data = data.replace(/\\n/g, ''); ct_$d = parseInt(data); return ct_$d;} );
|
|
var time = new Date(ct_$d);
|
|
var hours = time.getHours();
|
|
var minutes = time.getMinutes();
|
|
var seconds = time.getSeconds();
|
|
}
|
|
|
|
if (watchkind_$d == 'staticwatch') {
|
|
var hours_$d = '$h';
|
|
var minutes_$d = '$m';
|
|
var seconds_$d = '$s';
|
|
}
|
|
|
|
if (watchkind_$d == 'stopwatch') {
|
|
devName_$d = '$d';
|
|
|
|
command = '{ReadingsVal(\"'+devName_$d+'\",\"state\",\"\")}';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {
|
|
state_$d = data.replace(/\\n/g, '');
|
|
afree_$d = 0; // die Alarmierung zu Beginn nicht freischalten
|
|
return (state_$d, afree_$d);
|
|
}
|
|
);
|
|
|
|
if (state_$d == 'started' || state_$d == 'resumed') {
|
|
// == Startzeit ==
|
|
command = '{ReadingsNum(\"'+devName_$d+'\",\"starttime\", 0)}';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {data = data.replace(/\\n/g, ''); st_$d = parseInt(data); return st_$d;} );
|
|
|
|
startDate_$d = new Date(st_$d);
|
|
|
|
// aktueller Timestamp in Millisekunden
|
|
command = '{ int(time*1000) }';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {
|
|
data = data.replace(/\\n/g, '');
|
|
ct_$d = parseInt(data);
|
|
afree_$d = 1; // die Alarmierung freischalten
|
|
return (ct_$d, afree_$d);
|
|
}
|
|
);
|
|
|
|
currDate_$d = new Date(ct_$d);
|
|
elapsesec_$d = ((currDate_$d.getTime() - startDate_$d.getTime()))/1000; // vergangene Millisekunden in Sekunden
|
|
|
|
if (state_$d == 'resumed') {
|
|
lastsumsec_$d = localStorage.getItem('ss_$d');
|
|
afree_$d = 0; // beim 'resume' keine erneute Alarmierung
|
|
elapsesec_$d = parseInt(elapsesec_$d) + parseInt(lastsumsec_$d);
|
|
} else {
|
|
elapsesec_$d = parseInt(elapsesec_$d);
|
|
}
|
|
|
|
hours_$d = parseInt(elapsesec_$d / 3600);
|
|
elapsesec_$d -= hours_$d * 3600;
|
|
minutes_$d = parseInt(elapsesec_$d / 60);
|
|
seconds_$d = parseInt(elapsesec_$d - minutes_$d * 60);
|
|
|
|
var act = $ddt;
|
|
if (act == '$alarm' && act != ' $alarmdef' && afree_$d == 1) {
|
|
command = '{ CommandSetReading(undef, \"'+devName_$d+' alarmed '+act+'\") }';
|
|
url_$d = makeCommand(command);
|
|
|
|
\$.get(url_$d, function (data) {
|
|
command = '{ CommandSetReading(undef, \"'+devName_$d+' state stopped\") }';
|
|
url_$d = makeCommand(command);
|
|
\$.get(url_$d);
|
|
}
|
|
);
|
|
}
|
|
|
|
localStoreSet (hours_$d, minutes_$d, seconds_$d, NaN);
|
|
}
|
|
|
|
if (state_$d == 'stopped') {
|
|
hours_$d = localStorage.getItem('h_$d');
|
|
minutes_$d = localStorage.getItem('m_$d');
|
|
seconds_$d = localStorage.getItem('s_$d');
|
|
|
|
sumsecs_$d = parseInt(hours_$d*3600) + parseInt(minutes_$d*60) + parseInt(seconds_$d);
|
|
localStoreSet (NaN, NaN, NaN, sumsecs_$d);
|
|
}
|
|
|
|
if (state_$d == 'initialized') {
|
|
hours_$d = 0;
|
|
minutes_$d = 0;
|
|
seconds_$d = 0;
|
|
|
|
localStoreSet (hours_$d, minutes_$d, seconds_$d);
|
|
}
|
|
}
|
|
|
|
if (watchkind_$d == 'countdownwatch') {
|
|
devName_$d = '$d';
|
|
|
|
command = '{ReadingsVal(\"'+devName_$d+'\",\"state\",\"\")}';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {
|
|
state_$d = data.replace(/\\n/g, '');
|
|
afree_$d = 0; // die Alarmierung zu Beginn nicht freischalten
|
|
return (state_$d, afree_$d);
|
|
}
|
|
);
|
|
|
|
if (state_$d == 'started') {
|
|
// == Ermittlung Countdown Startwert ==
|
|
command = '{ReadingsNum(\"'+devName_$d+'\",\"countInitVal\", 0)}';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {
|
|
data = data.replace(/\\n/g, '');
|
|
ci_$d = parseInt(data);
|
|
return ci_$d;
|
|
}
|
|
);
|
|
|
|
countInitVal_$d = ci_$d; // Initialwert Countdown in Sekunden
|
|
|
|
// == Ermittlung vergangene Sekunden ==
|
|
command = '{ReadingsNum(\"'+devName_$d+'\",\"starttime\", 0)}';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {
|
|
data = data.replace(/\\n/g, '');
|
|
st_$d = parseInt(data);
|
|
return st_$d;
|
|
}
|
|
);
|
|
|
|
startDate_$d = new Date(st_$d);
|
|
|
|
// aktueller Timestamp in Millisekunden
|
|
command = '{ int(time*1000) }';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {
|
|
data = data.replace(/\\n/g, '');
|
|
ct_$d = parseInt(data);
|
|
afree_$d = 1; // die Alarmierung freischalten
|
|
return (ct_$d,afree_$d);
|
|
}
|
|
);
|
|
|
|
currDate_$d = new Date(ct_$d);
|
|
|
|
elapsesec_$d = ((currDate_$d.getTime() - startDate_$d.getTime()))/1000; // vergangene Millisekunden in Sekunden umrechnen
|
|
|
|
// == Countdown errechnen ==
|
|
countcurr_$d = countInitVal_$d - elapsesec_$d;
|
|
if (countcurr_$d < 0) {
|
|
countcurr_$d = 0;
|
|
}
|
|
//log(\"countcurr_$d: \"+countcurr_$d);
|
|
|
|
hours_$d = parseInt(countcurr_$d / 3600);
|
|
countcurr_$d -= hours_$d * 3600;
|
|
minutes_$d = parseInt(countcurr_$d / 60);
|
|
seconds_$d = parseInt(countcurr_$d - minutes_$d * 60);
|
|
|
|
var act = $ddt;
|
|
if ((act == '$alarm' || act == ' $alarmdef' ) && afree_$d == 1) {
|
|
command = '{ CommandSetReading(undef, \"'+devName_$d+' alarmed '+act+'\") }';
|
|
url_$d = makeCommand(command);
|
|
|
|
\$.get(url_$d, function (data) {
|
|
command = '{ CommandSetReading(undef, \"'+devName_$d+' state stopped\") }';
|
|
url_$d = makeCommand(command);
|
|
\$.get(url_$d);
|
|
}
|
|
);
|
|
}
|
|
|
|
localStoreSet (hours_$d, minutes_$d, seconds_$d);
|
|
|
|
}
|
|
|
|
if (state_$d == 'stopped') {
|
|
hours_$d = localStorage.getItem('h_$d');
|
|
minutes_$d = localStorage.getItem('m_$d');
|
|
seconds_$d = localStorage.getItem('s_$d');
|
|
}
|
|
|
|
if (state_$d == 'initialized') {
|
|
hours_$d = 0;
|
|
minutes_$d = 0;
|
|
seconds_$d = 0;
|
|
|
|
localStoreSet (hours_$d, minutes_$d, seconds_$d);
|
|
}
|
|
}
|
|
|
|
var value = $ddt;
|
|
|
|
if(value == ' undefined:undefined:undefined' || value == ' NaN:NaN:NaN') {
|
|
value = ' : : ';
|
|
}
|
|
|
|
display_$d.setValue(value);
|
|
window.setTimeout('animate_$d()', 200);
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|
|
";
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_station {
|
|
my ($d) = @_;
|
|
my $hash = $defs{$d};
|
|
my $ssh = AttrVal($d,"stationSecondHand","Bar")."SecondHand";
|
|
my $shb = AttrVal($d,"stationSecondHandBehavoir","Bouncing")."SecondHand";
|
|
my $smh = AttrVal($d,"stationMinuteHand","Pointed")."MinuteHand";
|
|
my $mhb = AttrVal($d,"stationMinuteHandBehavoir","Bouncing")."MinuteHand";
|
|
my $shh = AttrVal($d,"stationHourHand","Pointed")."HourHand";
|
|
my $sb = AttrVal($d,"stationBoss","Red")."Boss";
|
|
my $ssd = AttrVal($d,"stationStrokeDial","Swiss")."StrokeDial";
|
|
my $sbody = AttrVal($d,"stationBody","Round")."Body";
|
|
my $hattr = AttrVal($d,"htmlattr","width='150' height='150'");
|
|
my $tsou = AttrVal($d,"timeSource","server");
|
|
|
|
# Bahnhofsuhr aus http://www.3quarks.com/de/Bahnhofsuhr/
|
|
return "
|
|
<html>
|
|
<body>
|
|
<canvas id='clock_$d' $hattr>
|
|
</canvas>
|
|
|
|
<script>
|
|
|
|
var ct_$d;
|
|
var time;
|
|
|
|
// CSRF-Token auslesen
|
|
var body = document.querySelector(\"body\");
|
|
if( body != null ) {
|
|
csrf = body.getAttribute(\"fwcsrf\");
|
|
}
|
|
|
|
// get the base url
|
|
function getBaseUrl () {
|
|
var url = window.location.href.split(\"?\")[0];
|
|
url += \"?\";
|
|
if( csrf != null ) {
|
|
url += \"fwcsrf=\"+csrf+\"&\";
|
|
}
|
|
return url;
|
|
}
|
|
|
|
function makeCommand (cmd) {
|
|
return getBaseUrl()+\"cmd=\"+encodeURIComponent(cmd)+\"&XHR=1\";
|
|
}
|
|
|
|
// clock body (Uhrgehäuse)
|
|
StationClock_$d.NoBody = 0;
|
|
StationClock_$d.SmallWhiteBody = 1;
|
|
StationClock_$d.RoundBody = 2;
|
|
StationClock_$d.RoundGreenBody = 3;
|
|
StationClock_$d.SquareBody = 4;
|
|
StationClock_$d.ViennaBody = 5;
|
|
|
|
// stroke dial (Zifferblatt)
|
|
StationClock_$d.NoDial = 0;
|
|
StationClock_$d.GermanHourStrokeDial = 1;
|
|
StationClock_$d.GermanStrokeDial = 2;
|
|
StationClock_$d.AustriaStrokeDial = 3;
|
|
StationClock_$d.SwissStrokeDial = 4;
|
|
StationClock_$d.ViennaStrokeDial = 5;
|
|
|
|
//clock hour hand (Stundenzeiger)
|
|
StationClock_$d.PointedHourHand = 1;
|
|
StationClock_$d.BarHourHand = 2;
|
|
StationClock_$d.SwissHourHand = 3;
|
|
StationClock_$d.ViennaHourHand = 4;
|
|
|
|
//clock minute hand (Minutenzeiger)
|
|
StationClock_$d.PointedMinuteHand = 1;
|
|
StationClock_$d.BarMinuteHand = 2;
|
|
StationClock_$d.SwissMinuteHand = 3;
|
|
StationClock_$d.ViennaMinuteHand = 4;
|
|
|
|
//clock second hand (Sekundenzeiger)
|
|
StationClock_$d.NoSecondHand = 0;
|
|
StationClock_$d.BarSecondHand = 1;
|
|
StationClock_$d.HoleShapedSecondHand = 2;
|
|
StationClock_$d.NewHoleShapedSecondHand = 3;
|
|
StationClock_$d.SwissSecondHand = 4;
|
|
|
|
// clock boss (Zeigerabdeckung)
|
|
StationClock_$d.NoBoss = 0;
|
|
StationClock_$d.BlackBoss = 1;
|
|
StationClock_$d.RedBoss = 2;
|
|
StationClock_$d.ViennaBoss = 3;
|
|
|
|
// minute hand behavoir
|
|
StationClock_$d.CreepingMinuteHand = 0;
|
|
StationClock_$d.BouncingMinuteHand = 1;
|
|
StationClock_$d.ElasticBouncingMinuteHand = 2;
|
|
|
|
// second hand behavoir
|
|
StationClock_$d.CreepingSecondHand = 0;
|
|
StationClock_$d.BouncingSecondHand = 1;
|
|
StationClock_$d.ElasticBouncingSecondHand = 2;
|
|
StationClock_$d.OverhastySecondHand = 3;
|
|
|
|
|
|
function StationClock_$d(clockId_$d) {
|
|
this.clockId_$d = clockId_$d;
|
|
this.radius = 0;
|
|
|
|
// hour offset
|
|
this.hourOffset = 0;
|
|
|
|
// clock body
|
|
this.body = StationClock_$d.RoundBody;
|
|
this.bodyShadowColor = 'rgba(0,0,0,0.5)';
|
|
this.bodyShadowOffsetX = 0.03;
|
|
this.bodyShadowOffsetY = 0.03;
|
|
this.bodyShadowBlur = 0.06;
|
|
|
|
// body dial
|
|
this.dial = StationClock_$d.GermanStrokeDial;
|
|
this.dialColor = 'rgb(60,60,60)';
|
|
|
|
// clock hands
|
|
this.hourHand = StationClock_$d.PointedHourHand;
|
|
this.minuteHand = StationClock_$d.PointedMinuteHand;
|
|
this.secondHand = StationClock_$d.HoleShapedSecondHand;
|
|
this.handShadowColor = 'rgba(0,0,0,0.3)';
|
|
this.handShadowOffsetX = 0.03;
|
|
this.handShadowOffsetY = 0.03;
|
|
this.handShadowBlur = 0.04;
|
|
|
|
// clock colors
|
|
this.hourHandColor = 'rgb(0,0,0)';
|
|
this.minuteHandColor = 'rgb(0,0,0)';
|
|
this.secondHandColor = 'rgb(200,0,0)';
|
|
|
|
// clock boss
|
|
this.boss = StationClock_$d.NoBoss;
|
|
this.bossShadowColor = 'rgba(0,0,0,0.2)';
|
|
this.bossShadowOffsetX = 0.02;
|
|
this.bossShadowOffsetY = 0.02;
|
|
this.bossShadowBlur = 0.03;
|
|
|
|
// hand behavoir
|
|
this.minuteHandBehavoir = StationClock_$d.CreepingMinuteHand;
|
|
this.secondHandBehavoir = StationClock_$d.OverhastySecondHand;
|
|
|
|
// hand animation
|
|
this.minuteHandAnimationStep = 0;
|
|
this.secondHandAnimationStep = 0;
|
|
this.lastMinute = 0;
|
|
this.lastSecond = 0;
|
|
};
|
|
|
|
StationClock_$d.prototype.draw = function() {
|
|
var clock_$d = document.getElementById(this.clockId_$d);
|
|
|
|
if (clock_$d) {
|
|
var context = clock_$d.getContext('2d');
|
|
if (context) {
|
|
this.radius = 0.75 * (Math.min(clock_$d.width, clock_$d.height) / 2);
|
|
|
|
// clear canvas and set new origin
|
|
context.clearRect(0, 0, clock_$d.width, clock_$d.height);
|
|
context.save();
|
|
context.translate(clock_$d.width / 2, clock_$d.height / 2);
|
|
|
|
// draw body
|
|
if (this.body != StationClock_$d.NoStrokeBody) {
|
|
context.save();
|
|
switch (this.body) {
|
|
case StationClock_$d.SmallWhiteBody:
|
|
this.fillCircle(context, 'rgb(255,255,255)', 0, 0, 1);
|
|
break;
|
|
case StationClock_$d.RoundBody:
|
|
this.fillCircle(context, 'rgb(255,255,255)', 0, 0, 1.1);
|
|
context.save();
|
|
this.setShadow(context, this.bodyShadowColor, this.bodyShadowOffsetX, this.bodyShadowOffsetY, this.bodyShadowBlur);
|
|
this.strokeCircle(context, 'rgb(0,0,0)', 0, 0, 1.1, 0.07);
|
|
context.restore();
|
|
break;
|
|
case StationClock_$d.RoundGreenBody:
|
|
this.fillCircle(context, 'rgb(235,236,212)', 0, 0, 1.1);
|
|
context.save();
|
|
this.setShadow(context, this.bodyShadowColor, this.bodyShadowOffsetX, this.bodyShadowOffsetY, this.bodyShadowBlur);
|
|
this.strokeCircle(context, 'rgb(180,180,180)', 0, 0, 1.1, 0.2);
|
|
context.restore();
|
|
this.strokeCircle(context, 'rgb(29,84,31)', 0, 0, 1.15, 0.1);
|
|
context.save();
|
|
this.setShadow(context, 'rgba(235,236,212,100)', -0.02, -0.02, 0.09);
|
|
this.strokeCircle(context, 'rgb(76,128,110)', 0, 0, 1.1, 0.08);
|
|
context.restore();
|
|
break;
|
|
case StationClock_$d.SquareBody:
|
|
context.save();
|
|
this.setShadow(context, this.bodyShadowColor, this.bodyShadowOffsetX, this.bodyShadowOffsetY, this.bodyShadowBlur);
|
|
this.fillSquare(context, 'rgb(237,235,226)', 0, 0, 2.4);
|
|
this.strokeSquare(context, 'rgb(38,106,186)', 0, 0, 2.32, 0.16);
|
|
context.restore();
|
|
context.save();
|
|
this.setShadow(context, this.bodyShadowColor, this.bodyShadowOffsetX, this.bodyShadowOffsetY, this.bodyShadowBlur);
|
|
this.strokeSquare(context, 'rgb(42,119,208)', 0, 0, 2.24, 0.08);
|
|
context.restore();
|
|
break;
|
|
case StationClock_$d.ViennaBody:
|
|
context.save();
|
|
this.fillSymmetricPolygon(context, 'rgb(156,156,156)', [[-1.2,1.2],[-1.2,-1.2]],0.1);
|
|
this.fillPolygon(context, 'rgb(156,156,156)', 0,1.2 , 1.2,1.2 , 1.2,0);
|
|
this.fillCircle(context, 'rgb(255,255,255)', 0, 0, 1.05, 0.08);
|
|
this.strokeCircle(context, 'rgb(0,0,0)', 0, 0, 1.05, 0.01);
|
|
this.strokeCircle(context, 'rgb(100,100,100)', 0, 0, 1.1, 0.01);
|
|
this.fillPolygon(context, 'rgb(100,100,100)', 0.45,1.2 , 1.2,1.2 , 1.2,0.45);
|
|
this.fillPolygon(context, 'rgb(170,170,170)', 0.45,-1.2 , 1.2,-1.2 , 1.2,-0.45);
|
|
this.fillPolygon(context, 'rgb(120,120,120)', -0.45,1.2 , -1.2,1.2 , -1.2,0.45);
|
|
this.fillPolygon(context, 'rgb(200,200,200)', -0.45,-1.2 , -1.2,-1.2 , -1.2,-0.45);
|
|
this.strokeSymmetricPolygon(context, 'rgb(156,156,156)', [[-1.2,1.2],[-1.2,-1.2]],0.01);
|
|
this.fillPolygon(context, 'rgb(255,0,0)', 0.05,-0.6 , 0.15,-0.6 , 0.15,-0.45 , 0.05,-0.45);
|
|
this.fillPolygon(context, 'rgb(255,0,0)', -0.05,-0.6 , -0.15,-0.6 , -0.15,-0.45 , -0.05,-0.45);
|
|
this.fillPolygon(context, 'rgb(255,0,0)', 0.05,-0.35 , 0.15,-0.35 , 0.15,-0.30 , 0.10,-0.20 , 0.05,-0.20);
|
|
this.fillPolygon(context, 'rgb(255,0,0)', -0.05,-0.35 , -0.15,-0.35 , -0.15,-0.30 , -0.10,-0.20 , -0.05,-0.20);
|
|
context.restore();
|
|
break;
|
|
}
|
|
context.restore();
|
|
}
|
|
|
|
// draw dial
|
|
for (var i = 0; i < 60; i++) {
|
|
context.save();
|
|
context.rotate(i * Math.PI / 30);
|
|
switch (this.dial) {
|
|
case StationClock_$d.SwissStrokeDial:
|
|
if ((i % 5) == 0) {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.75, 0.07);
|
|
} else {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.92, 0.026);
|
|
}
|
|
break;
|
|
case StationClock_$d.AustriaStrokeDial:
|
|
if ((i % 5) == 0) {
|
|
this.fillPolygon(context, this.dialColor, -0.04, -1.0, 0.04, -1.0, 0.03, -0.78, -0.03, -0.78);
|
|
} else {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.94, 0.02);
|
|
}
|
|
break;
|
|
case StationClock_$d.GermanStrokeDial:
|
|
if ((i % 15) == 0) {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.70, 0.08);
|
|
} else if ((i % 5) == 0) {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.76, 0.08);
|
|
} else {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.92, 0.036);
|
|
}
|
|
break;
|
|
case StationClock_$d.GermanHourStrokeDial:
|
|
if ((i % 15) == 0) {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.70, 0.10);
|
|
} else if ((i % 5) == 0) {
|
|
this.strokeLine(context, this.dialColor, 0.0, -1.0, 0.0, -0.74, 0.08);
|
|
}
|
|
break;
|
|
case StationClock_$d.ViennaStrokeDial:
|
|
if ((i % 15) == 0) {
|
|
this.fillPolygon(context, this.dialColor, 0.7,-0.1, 0.6,0, 0.7,0.1, 1,0.03, 1,-0.03);
|
|
} else if ((i % 5) == 0) {
|
|
this.fillPolygon(context, this.dialColor, 0.85,-0.06, 0.78,0, 0.85,0.06, 1,0.03, 1,-0.03);
|
|
}
|
|
this.fillCircle(context, this.dialColor, 0.0, -1.0, 0.03);
|
|
break;
|
|
}
|
|
context.restore();
|
|
}
|
|
|
|
// Zeitsteuerung
|
|
if ('$tsou' == 'server') {
|
|
// aktueller Timestamp in Millisekunden
|
|
command = '{ int(time*1000) }';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {data = data.replace(/\\n/g, ''); ct_$d = parseInt(data); return ct_$d;} );
|
|
}
|
|
if (typeof ct_$d === 'undefined') {
|
|
time_$d = new Date(); // mit lokaler Zeit initialisieren -> Clientzeit || Serverzeit: springen Zeiger verhindern
|
|
} else {
|
|
time_$d = new Date(ct_$d);
|
|
}
|
|
|
|
var millis = time_$d.getMilliseconds() / 1000.0;
|
|
var seconds = time_$d.getSeconds();
|
|
var minutes = time_$d.getMinutes();
|
|
var hours = time_$d.getHours() + this.hourOffset;
|
|
|
|
// draw hour hand
|
|
context.save();
|
|
context.rotate(hours * Math.PI / 6 + minutes * Math.PI / 360);
|
|
this.setShadow(context, this.handShadowColor, this.handShadowOffsetX, this.handShadowOffsetY, this.handShadowBlur);
|
|
switch (this.hourHand) {
|
|
case StationClock_$d.BarHourHand:
|
|
this.fillPolygon(context, this.hourHandColor, -0.05, -0.6, 0.05, -0.6, 0.05, 0.15, -0.05, 0.15);
|
|
break;
|
|
case StationClock_$d.PointedHourHand:
|
|
this.fillPolygon(context, this.hourHandColor, 0.0, -0.6, 0.065, -0.53, 0.065, 0.19, -0.065, 0.19, -0.065, -0.53);
|
|
break;
|
|
case StationClock_$d.SwissHourHand:
|
|
this.fillPolygon(context, this.hourHandColor, -0.05, -0.6, 0.05, -0.6, 0.065, 0.26, -0.065, 0.26);
|
|
break;
|
|
case StationClock_$d.ViennaHourHand:
|
|
this.fillSymmetricPolygon(context, this.hourHandColor, [[-0.02,-0.72],[-0.08,-0.56],[-0.15,-0.45],[-0.06,-0.30],[-0.03,0],[-0.1,0.2],[-0.05,0.23],[-0.03,0.2]]);
|
|
}
|
|
context.restore();
|
|
|
|
// draw minute hand
|
|
context.save();
|
|
switch (this.minuteHandBehavoir) {
|
|
case StationClock_$d.CreepingMinuteHand:
|
|
context.rotate((minutes + seconds / 60) * Math.PI / 30);
|
|
break;
|
|
case StationClock_$d.BouncingMinuteHand:
|
|
context.rotate(minutes * Math.PI / 30);
|
|
break;
|
|
case StationClock_$d.ElasticBouncingMinuteHand:
|
|
if (this.lastMinute != minutes) {
|
|
this.minuteHandAnimationStep = 3;
|
|
this.lastMinute = minutes;
|
|
}
|
|
context.rotate((minutes + this.getAnimationOffset(this.minuteHandAnimationStep)) * Math.PI / 30);
|
|
this.minuteHandAnimationStep--;
|
|
break;
|
|
}
|
|
this.setShadow(context, this.handShadowColor, this.handShadowOffsetX, this.handShadowOffsetY, this.handShadowBlur);
|
|
switch (this.minuteHand) {
|
|
case StationClock_$d.BarMinuteHand:
|
|
this.fillPolygon(context, this.minuteHandColor, -0.05, -0.9, 0.035, -0.9, 0.035, 0.23, -0.05, 0.23);
|
|
break;
|
|
case StationClock_$d.PointedMinuteHand:
|
|
this.fillPolygon(context, this.minuteHandColor, 0.0, -0.93, 0.045, -0.885, 0.045, 0.23, -0.045, 0.23, -0.045, -0.885);
|
|
break;
|
|
case StationClock_$d.SwissMinuteHand:
|
|
this.fillPolygon(context, this.minuteHandColor, -0.035, -0.93, 0.035, -0.93, 0.05, 0.25, -0.05, 0.25);
|
|
break;
|
|
case StationClock_$d.ViennaMinuteHand:
|
|
this.fillSymmetricPolygon(context, this.minuteHandColor, [[-0.02,-0.98],[-0.09,-0.7],[-0.03,0],[-0.05,0.2],[-0.01,0.4]]);
|
|
}
|
|
context.restore();
|
|
|
|
// draw second hand
|
|
context.save();
|
|
switch (this.secondHandBehavoir) {
|
|
case StationClock_$d.OverhastySecondHand:
|
|
context.rotate(Math.min((seconds + millis) * (60.0 / 58.5), 60.0) * Math.PI / 30);
|
|
break;
|
|
case StationClock_$d.CreepingSecondHand:
|
|
context.rotate((seconds + millis) * Math.PI / 30);
|
|
break;
|
|
case StationClock_$d.BouncingSecondHand:
|
|
context.rotate(seconds * Math.PI / 30);
|
|
break;
|
|
case StationClock_$d.ElasticBouncingSecondHand:
|
|
if (this.lastSecond != seconds) {
|
|
this.secondHandAnimationStep = 3;
|
|
this.lastSecond = seconds;
|
|
}
|
|
context.rotate((seconds + this.getAnimationOffset(this.secondHandAnimationStep)) * Math.PI / 30);
|
|
this.secondHandAnimationStep--;
|
|
break;
|
|
}
|
|
this.setShadow(context, this.handShadowColor, this.handShadowOffsetX, this.handShadowOffsetY, this.handShadowBlur);
|
|
switch (this.secondHand) {
|
|
case StationClock_$d.BarSecondHand:
|
|
this.fillPolygon(context, this.secondHandColor, -0.006, -0.92, 0.006, -0.92, 0.028, 0.23, -0.028, 0.23);
|
|
break;
|
|
case StationClock_$d.HoleShapedSecondHand:
|
|
this.fillPolygon(context, this.secondHandColor, 0.0, -0.9, 0.011, -0.889, 0.01875, -0.6, -0.01875, -0.6, -0.011, -0.889);
|
|
this.fillPolygon(context, this.secondHandColor, 0.02, -0.4, 0.025, 0.22, -0.025, 0.22, -0.02, -0.4);
|
|
this.strokeCircle(context, this.secondHandColor, 0, -0.5, 0.083, 0.066);
|
|
break;
|
|
case StationClock_$d.NewHoleShapedSecondHand:
|
|
this.fillPolygon(context, this.secondHandColor, 0.0, -0.95, 0.015, -0.935, 0.0187, -0.65, -0.0187, -0.65, -0.015, -0.935);
|
|
this.fillPolygon(context, this.secondHandColor, 0.022, -0.45, 0.03, 0.27, -0.03, 0.27, -0.022, -0.45);
|
|
this.strokeCircle(context, this.secondHandColor, 0, -0.55, 0.085, 0.07);
|
|
break;
|
|
case StationClock_$d.SwissSecondHand:
|
|
this.strokeLine(context, this.secondHandColor, 0.0, -0.6, 0.0, 0.35, 0.026);
|
|
this.fillCircle(context, this.secondHandColor, 0, -0.64, 0.1);
|
|
break;
|
|
case StationClock_$d.ViennaSecondHand:
|
|
this.strokeLine(context, this.secondHandColor, 0.0, -0.6, 0.0, 0.35, 0.026);
|
|
this.fillCircle(context, this.secondHandColor, 0, -0.64, 0.1);
|
|
break;
|
|
}
|
|
context.restore();
|
|
|
|
// draw clock boss
|
|
if (this.boss != StationClock_$d.NoBoss) {
|
|
context.save();
|
|
this.setShadow(context, this.bossShadowColor, this.bossShadowOffsetX, this.bossShadowOffsetY, this.bossShadowBlur);
|
|
switch (this.boss) {
|
|
case StationClock_$d.BlackBoss:
|
|
this.fillCircle(context, 'rgb(0,0,0)', 0, 0, 0.1);
|
|
break;
|
|
case StationClock_$d.RedBoss:
|
|
this.fillCircle(context, 'rgb(220,0,0)', 0, 0, 0.06);
|
|
break;
|
|
case StationClock_$d.ViennaBoss:
|
|
this.fillCircle(context, 'rgb(0,0,0)', 0, 0, 0.07);
|
|
break;
|
|
}
|
|
context.restore();
|
|
}
|
|
context.restore();
|
|
}
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.getAnimationOffset = function(animationStep) {
|
|
switch (animationStep) {
|
|
case 3: return 0.2;
|
|
case 2: return -0.1;
|
|
case 1: return 0.05;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
StationClock_$d.prototype.setShadow = function(context, color, offsetX, offsetY, blur) {
|
|
if (color) {
|
|
context.shadowColor = color;
|
|
context.shadowOffsetX = this.radius * offsetX;
|
|
context.shadowOffsetY = this.radius * offsetY;
|
|
context.shadowBlur = this.radius * blur;
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.fillCircle = function(context, color, x, y, radius) {
|
|
if (color) {
|
|
context.beginPath();
|
|
context.fillStyle = color;
|
|
context.arc(x * this.radius, y * this.radius, radius * this.radius, 0, 2 * Math.PI, true);
|
|
context.fill();
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.strokeCircle = function(context, color, x, y, radius, lineWidth) {
|
|
if (color) {
|
|
context.beginPath();
|
|
context.strokeStyle = color;
|
|
context.lineWidth = lineWidth * this.radius;
|
|
context.arc(x * this.radius, y * this.radius, radius * this.radius, 0, 2 * Math.PI, true);
|
|
context.stroke();
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.fillSquare = function(context, color, x, y, size) {
|
|
if (color) {
|
|
context.fillStyle = color;
|
|
context.fillRect((x - size / 2) * this.radius, (y -size / 2) * this.radius, size * this.radius, size * this.radius);
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.strokeSquare = function(context, color, x, y, size, lineWidth) {
|
|
if (color) {
|
|
context.strokeStyle = color;
|
|
context.lineWidth = lineWidth * this.radius;
|
|
context.strokeRect((x - size / 2) * this.radius, (y -size / 2) * this.radius, size * this.radius, size * this.radius);
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.strokeLine = function(context, color, x1, y1, x2, y2, width) {
|
|
if (color) {
|
|
context.beginPath();
|
|
context.strokeStyle = color;
|
|
context.moveTo(x1 * this.radius, y1 * this.radius);
|
|
context.lineTo(x2 * this.radius, y2 * this.radius);
|
|
context.lineWidth = width * this.radius;
|
|
context.stroke();
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.fillPolygon = function(context, color, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5) {
|
|
if (color) {
|
|
context.beginPath();
|
|
context.fillStyle = color;
|
|
context.moveTo(x1 * this.radius, y1 * this.radius);
|
|
context.lineTo(x2 * this.radius, y2 * this.radius);
|
|
context.lineTo(x3 * this.radius, y3 * this.radius);
|
|
context.lineTo(x4 * this.radius, y4 * this.radius);
|
|
if ((x5 != undefined) && (y5 != undefined)) {
|
|
context.lineTo(x5 * this.radius, y5 * this.radius);
|
|
}
|
|
context.lineTo(x1 * this.radius, y1 * this.radius);
|
|
context.fill();
|
|
}
|
|
};
|
|
|
|
StationClock_$d.prototype.fillSymmetricPolygon = function(context, color, points) {
|
|
context.beginPath();
|
|
context.fillStyle = color;
|
|
context.moveTo(points[0][0] * this.radius, points[0][1] * this.radius);
|
|
for (var i = 1; i < points.length; i++) {
|
|
context.lineTo(points[i][0] * this.radius, points[i][1] * this.radius);
|
|
}
|
|
for (var i = points.length - 1; i >= 0; i--) {
|
|
context.lineTo(0 - points[i][0] * this.radius, points[i][1] * this.radius);
|
|
}
|
|
context.lineTo(points[0][0] * this.radius, points[0][1] * this.radius);
|
|
context.fill();
|
|
};
|
|
|
|
StationClock_$d.prototype.strokeSymmetricPolygon = function(context, color, points, width) {
|
|
context.beginPath();
|
|
context.strokeStyle = color;
|
|
context.moveTo(points[0][0] * this.radius, points[0][1] * this.radius);
|
|
for (var i = 1; i < points.length; i++) {
|
|
context.lineTo(points[i][0] * this.radius, points[i][1] * this.radius);
|
|
}
|
|
for (var i = points.length - 1; i >= 0; i--) {
|
|
context.lineTo(0 - points[i][0] * this.radius, points[i][1] * this.radius);
|
|
}
|
|
context.lineTo(points[0][0] * this.radius, points[0][1] * this.radius);
|
|
context.lineWidth = width * this.radius;
|
|
context.stroke();
|
|
};
|
|
|
|
var clock_$d = new StationClock_$d('clock_$d');
|
|
clock_$d.body = StationClock_$d.$sbody;
|
|
clock_$d.dial = StationClock_$d.$ssd;
|
|
clock_$d.hourHand = StationClock_$d.$shh;
|
|
clock_$d.minuteHand = StationClock_$d.$smh;
|
|
clock_$d.secondHand = StationClock_$d.$ssh;
|
|
clock_$d.boss = StationClock_$d.$sb;
|
|
clock_$d.minuteHandBehavoir = StationClock_$d.$mhb;
|
|
clock_$d.secondHandBehavoir = StationClock_$d.$shb;
|
|
|
|
function animate(clock_$d) {
|
|
clock_$d.draw();
|
|
// window.setTimeout(function(){animate(clock_$d)}, 50); // alte Variante
|
|
window.setTimeout(function(){animate(clock_$d)}, 100);
|
|
}
|
|
|
|
animate(clock_$d);
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|
|
";
|
|
}
|
|
|
|
################################################################
|
|
sub Watches_modern {
|
|
my ($d) = @_;
|
|
my $hash = $defs{$d};
|
|
my $facec = AttrVal($d,"modernColorFace","FFFEFA");
|
|
my $bgc = AttrVal($d,"modernColorBackground","333");
|
|
my $fc = AttrVal($d,"modernColorFigure","333");
|
|
my $hc = AttrVal($d,"modernColorHand","333");
|
|
my $fr = AttrVal($d,"modernColorRing","FFFFFF");
|
|
my $fre = AttrVal($d,"modernColorRingEdge","333");
|
|
my $hattr = AttrVal($d,"htmlattr","width='150' height='150'");
|
|
my $tsou = AttrVal($d,"timeSource","server");
|
|
|
|
# moderne Uhr aus https://www.w3schools.com/graphics/canvas_clock_start.asp
|
|
return "
|
|
<html>
|
|
<body>
|
|
|
|
<canvas id='canvas_$d' $hattr style='background-color:#$bgc'>
|
|
</canvas>
|
|
|
|
<script>
|
|
|
|
var ct_$d;
|
|
var now_$d;
|
|
|
|
// CSRF-Token auslesen
|
|
var body = document.querySelector(\"body\");
|
|
if( body != null ) {
|
|
csrf = body.getAttribute(\"fwcsrf\");
|
|
}
|
|
|
|
// get the base url
|
|
function getBaseUrl () {
|
|
var url = window.location.href.split(\"?\")[0];
|
|
url += \"?\";
|
|
if( csrf != null ) {
|
|
url += \"fwcsrf=\"+csrf+\"&\";
|
|
}
|
|
return url;
|
|
}
|
|
|
|
function makeCommand (cmd) {
|
|
return getBaseUrl()+\"cmd=\"+encodeURIComponent(cmd)+\"&XHR=1\";
|
|
}
|
|
|
|
var canvas_$d = document.getElementById('canvas_$d');
|
|
var ctx_$d = canvas_$d.getContext('2d');
|
|
var radius_$d = canvas_$d.height / 2;
|
|
|
|
ctx_$d.translate(radius_$d, radius_$d);
|
|
radius_$d = radius_$d * 0.90
|
|
// setInterval(drawClock_$d, 1000); // alte Variante
|
|
setInterval(drawClock_$d, 100);
|
|
|
|
function drawClock_$d() {
|
|
drawFace_$d (ctx_$d, radius_$d);
|
|
drawnumbers_$d (ctx_$d, radius_$d);
|
|
drawTime_$d (ctx_$d, radius_$d);
|
|
}
|
|
|
|
function drawFace_$d(ctx_$d, radius_$d) {
|
|
var grad_$d;
|
|
ctx_$d.beginPath();
|
|
ctx_$d.arc(0, 0, radius_$d, 0, 2*Math.PI);
|
|
ctx_$d.fillStyle = '#$facec'; // Füllung Uhr
|
|
ctx_$d.fill();
|
|
grad_$d = ctx_$d.createRadialGradient(0,0,radius_$d*0.95, 0,0,radius_$d*1.05);
|
|
grad_$d.addColorStop(0, '#$hc'); // Farbe Zeiger und innere Ringgrenze
|
|
grad_$d.addColorStop(0.5, '#$fr'); // Farbe Ziffernblattring
|
|
grad_$d.addColorStop(1, '#$fre'); // Farbe äußere Ringgrenze
|
|
ctx_$d.strokeStyle = grad_$d;
|
|
ctx_$d.lineWidth = radius_$d*0.1;
|
|
ctx_$d.stroke();
|
|
ctx_$d.beginPath();
|
|
ctx_$d.arc(0, 0, radius_$d*0.1, 0, 2*Math.PI);
|
|
ctx_$d.fillStyle = '#$fc'; // Farbe Ziffern und Zeigerwelle
|
|
ctx_$d.fill();
|
|
}
|
|
|
|
function drawnumbers_$d(ctx_$d, radius_$d) {
|
|
var ang_$d;
|
|
var num_$d;
|
|
ctx_$d.font = radius_$d*0.15 + 'px arial';
|
|
ctx_$d.textBaseline ='middle';
|
|
ctx_$d.textAlign ='center';
|
|
|
|
for(num_$d = 1; num_$d < 13; num_$d++){
|
|
ang_$d = num_$d * Math.PI / 6;
|
|
ctx_$d.rotate(ang_$d);
|
|
ctx_$d.translate(0, -radius_$d*0.85);
|
|
ctx_$d.rotate(-ang_$d);
|
|
ctx_$d.fillText(num_$d.toString(), 0, 0);
|
|
ctx_$d.rotate(ang_$d);
|
|
ctx_$d.translate(0, radius_$d*0.85);
|
|
ctx_$d.rotate(-ang_$d);
|
|
}
|
|
}
|
|
|
|
function drawTime_$d(ctx_$d, radius_$d){
|
|
// Zeitsteuerung
|
|
if ('$tsou' == 'server') {
|
|
// aktueller Timestamp in Millisekunden
|
|
command = '{ int(time*1000) }';
|
|
url_$d = makeCommand(command);
|
|
\$.get( url_$d, function (data) {data = data.replace(/\\n/g, ''); ct_$d = parseInt(data); return ct_$d;} );
|
|
}
|
|
if (typeof ct_$d === 'undefined') {
|
|
time_$d = new Date(); // mit lokaler Zeit initialisieren -> springen Zeiger verhindern
|
|
} else {
|
|
time_$d = new Date(ct_$d);
|
|
}
|
|
|
|
var hour_$d = time_$d.getHours();
|
|
var minute_$d = time_$d.getMinutes();
|
|
var second_$d = time_$d.getSeconds();
|
|
|
|
//hour_$d
|
|
hour_$d = hour_$d%12;
|
|
hour_$d = (hour_$d*Math.PI/6)+
|
|
(minute_$d*Math.PI/(6*60))+
|
|
(second_$d*Math.PI/(360*60));
|
|
drawHand_$d(ctx_$d, hour_$d, radius_$d*0.5, radius_$d*0.07);
|
|
|
|
//minute_$d
|
|
minute_$d = (minute_$d*Math.PI/30)+(second_$d*Math.PI/(30*60));
|
|
drawHand_$d(ctx_$d, minute_$d, radius_$d*0.8, radius_$d*0.07);
|
|
|
|
// second_$d
|
|
second_$d = (second_$d*Math.PI/30);
|
|
drawHand_$d(ctx_$d, second_$d, radius_$d*0.9, radius_$d*0.02);
|
|
}
|
|
|
|
function drawHand_$d(ctx_$d, pos, length, width) {
|
|
ctx_$d.beginPath();
|
|
ctx_$d.lineWidth = width;
|
|
ctx_$d.lineCap = 'round';
|
|
ctx_$d.moveTo(0,0);
|
|
ctx_$d.rotate(pos);
|
|
ctx_$d.lineTo(0, -length);
|
|
ctx_$d.stroke();
|
|
ctx_$d.rotate(-pos);
|
|
}
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|
|
";
|
|
}
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item helper
|
|
=item summary create a watch in modern, station or digital style
|
|
=item summary_DE erstellt eine Uhr: Modern, Bahnhofsuhr oder Digital
|
|
|
|
=begin html
|
|
|
|
<a name="Watches"></a>
|
|
<h3>Watches</h3>
|
|
|
|
At the moment only a german commandref is available.
|
|
|
|
=end html
|
|
=begin html_DE
|
|
|
|
<a name="Watches"></a>
|
|
<h3>Watches</h3>
|
|
|
|
<br>
|
|
Das Modul Watches stellt eine Modern-, Bahnhofs- oder Digitalanzeige als Device zur Verfügung. <br>
|
|
Die Uhren basieren auf Skripten dieser Seiten: <br>
|
|
<a href='https://www.w3schools.com/graphics/canvas_clock_start.asp'>moderne Uhr</a>,
|
|
<a href='http://www.3quarks.com/de/Bahnhofsuhr/'>Bahnhofsuhr</a>,
|
|
<a href='http://www.3quarks.com/de/Segmentanzeige/'>Digitalanzeige</a>
|
|
<br>
|
|
<br>
|
|
Als Zeitquelle können sowohl der Client (Browserzeit) als auch der FHEM-Server eingestellt werden
|
|
(Attribut <a href="#timeSource">timeSource</a>). <br>
|
|
|
|
<ul>
|
|
<a name="WatchesDefine"></a>
|
|
<b>Define</b>
|
|
|
|
<ul>
|
|
define <name> Watches [Modern | Station | Digital]
|
|
<br><br>
|
|
|
|
<table>
|
|
<colgroup> <col width=5%> <col width=95%> </colgroup>
|
|
<tr><td> <b>Modern</b> </td><td>: erstellt eine analoge Uhr im modernen Design </td></tr>
|
|
<tr><td> <b>Station</b> </td><td>: erstellt eine Bahnhofsuhr </td></tr>
|
|
<tr><td> <b>Digital</b> </td><td>: erstellt eine Digitalanzeige (Uhr, (CountDown)Stoppuhr, statische Zeitanzeige oder Text) </td></tr>
|
|
</table>
|
|
<br>
|
|
<br>
|
|
</ul>
|
|
|
|
<a name="WatchesSet"></a>
|
|
<b>Set</b>
|
|
|
|
<ul>
|
|
<ul>
|
|
|
|
<a name="alarmHMSset"></a>
|
|
<li><b>alarmHMSset <hh> <mm> <ss> </b><br>
|
|
Setzt die Alarmzeit im Format hh-Stunden(24), mm-Minuten und ss-Sekunden. <br>
|
|
Erreicht die Zeit den definierten Wert, wird ein Event des Readings "alarmed" erstellt. <br>
|
|
Die Stoppuhr hält an diesem Wert an. <br>
|
|
Wird eine CountDown-Stoppuhr mit "coninue" fortgesetzt, erfolgt ein nochmaliger alarmed-Event beim Erreichen der
|
|
Zeit 00:00:00. <br>
|
|
(default: 0 0 0) <br><br>
|
|
|
|
Dieses Set-Kommando ist nur bei digitalen Stoppuhren vorhanden. <br><br>
|
|
|
|
<ul>
|
|
<b>Beispiel</b> <br>
|
|
set <name> alarmHMSset 0 30 10
|
|
</ul>
|
|
<br>
|
|
|
|
</li>
|
|
<br>
|
|
|
|
<a name="alarmHMSdel"></a>
|
|
<li><b>alarmHMSdel</b><br>
|
|
Löscht die gesetzte Alarmzeit und deren Status. <br>
|
|
Dieses Set-Kommando ist nur bei digitalen Stoppuhren vorhanden. <br>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="continue"></a>
|
|
<li><b>continue</b><br>
|
|
Setzt die Zählung einer angehaltenen Stoppuhr inklusive der seit "start" abgelaufenen Zeit fort.
|
|
War die Stoppuhr noch nicht gestartet, beginnt die Zählung bei "00:00:00" (stopwatch) bzw. "countInitVal" (countdownwatch). <br>
|
|
Dieses Set-Kommando ist nur bei einer digitalen CountDown-Stoppuhr vorhanden. <br>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="countDownInit"></a>
|
|
<li><b>countDownInit <hh> <mm> <ss> </b><br>
|
|
Setzt die Startzeit einer CountDown-Stoppuhr mit hh-Stunden(24), mm-Minuten und ss-Sekunden. <br>
|
|
Dieses Set-Kommando ist nur bei einer digitalen CountDown-Stoppuhr vorhanden. <br><br>
|
|
|
|
<ul>
|
|
<b>Beispiel</b> <br>
|
|
set <name> countDownInit 0 30 10
|
|
</ul>
|
|
<br>
|
|
|
|
</li>
|
|
<br>
|
|
|
|
<a name="reset"></a>
|
|
<li><b>reset</b><br>
|
|
Stoppt die Stoppuhr (falls sie läuft) und löscht alle spezifischen Readings bzw. setzt sie auf initialized zurück. <br>
|
|
Dieses Set-Kommando ist nur bei digitalen Stoppuhren vorhanden. <br>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="resume"></a>
|
|
<li><b>resume</b><br>
|
|
Setzt die Zählung einer angehaltenen Stoppuhr fort. <br>
|
|
Dieses Set-Kommando ist nur bei einer digitalen Stoppuhr vorhanden. <br>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="start"></a>
|
|
<li><b>start</b><br>
|
|
Startet die Stoppuhr. <br>
|
|
Dieses Set-Kommando ist nur bei digitalen Stoppuhren vorhanden. <br>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stop"></a>
|
|
<li><b>stop</b><br>
|
|
Stoppt die Stoppuhr. Die erreichte Zeit bleibt erhalten. <br>
|
|
Dieses Set-Kommando ist nur bei digitalen Stoppuhren vorhanden. <br>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="time"></a>
|
|
<li><b>time <hh> <mm> <ss> </b><br>
|
|
Setzt eine statische Zeitanzeige mit hh-Stunden(24), mm-Minuten und ss-Sekunden. <br>
|
|
Dieses Set-Kommando ist nur bei einer Digitaluhr mit statischer Zeitanzeige vorhanden. <br><br>
|
|
|
|
<ul>
|
|
<b>Beispiel</b> <br>
|
|
set <name> time 8 15 3
|
|
</ul>
|
|
|
|
</li>
|
|
<br>
|
|
|
|
</ul>
|
|
</ul>
|
|
<br>
|
|
|
|
<a name="WatchesGet"></a>
|
|
<b>Get</b> <ul>N/A</ul><br>
|
|
|
|
<a name="WatchesAttr"></a>
|
|
<b>Attribute</b>
|
|
<br><br>
|
|
|
|
<ul>
|
|
<ul>
|
|
|
|
<a name="disable"></a>
|
|
<li><b>disable</b><br>
|
|
Aktiviert/deaktiviert das Device.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="hideDisplayName"></a>
|
|
<li><b>hideDisplayName</b><br>
|
|
Verbirgt den Device/Alias-Namen (Link zur Detailansicht).
|
|
</li>
|
|
<br>
|
|
|
|
<a name="htmlattr"></a>
|
|
<li><b>htmlattr</b><br>
|
|
Zusätzliche HTML Tags zur Größenänderung de Uhr. <br><br>
|
|
<ul>
|
|
<b>Beispiel: </b><br>
|
|
attr <name> htmlattr width="125" height="125" <br>
|
|
</ul>
|
|
</li>
|
|
<br>
|
|
|
|
<a name="timeSource"></a>
|
|
<li><b>timeSource</b><br>
|
|
Wählt die Zeitquelle aus. Es kann die lokale Clientzeit (Browser) oder die Zeit des FHEM-Servers angezeigt werden. <br>
|
|
Diese Einstellung ist bei (CountDown-)Stoppuhren nicht relevant. <br>
|
|
(default: server)
|
|
</li>
|
|
<br>
|
|
|
|
</ul>
|
|
|
|
Die nachfolgenden Attribute sind spezifisch für einen Uhrentyp zu setzen. <br>
|
|
<br>
|
|
|
|
<b>Model: Modern</b> <br><br>
|
|
|
|
<ul>
|
|
<a name="modernColorBackground"></a>
|
|
<li><b>modernColorBackground</b><br>
|
|
Hintergrundfarbe der Uhr.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="modernColorFace"></a>
|
|
<li><b>modernColorFace</b><br>
|
|
Einfärbung des Ziffernblattes.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="modernColorFigure"></a>
|
|
<li><b>modernColorFigure</b><br>
|
|
Farbe der Ziffern im Ziffernblatt und der Zeigerachsabdeckung.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="modernColorHand"></a>
|
|
<li><b>modernColorHand</b><br>
|
|
Farbe der UhrenZeiger.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="modernColorRing"></a>
|
|
<li><b>modernColorRing</b><br>
|
|
Farbe des Ziffernblattrahmens.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="modernColorRingEdge"></a>
|
|
<li><b>modernColorRingEdge</b><br>
|
|
Farbe des Außenringes vom Ziffernblattrahmen.
|
|
</li>
|
|
<br>
|
|
</ul>
|
|
<br>
|
|
|
|
<b>Model: Station</b> <br><br>
|
|
|
|
<ul>
|
|
<a name="stationBody"></a>
|
|
<li><b>stationBody</b><br>
|
|
Art des Uhrengehäuses.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationBoss"></a>
|
|
<li><b>stationBoss</b><br>
|
|
Art und Farbe der Zeigerachsabdeckung.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationHourHand"></a>
|
|
<li><b>stationHourHand</b><br>
|
|
Art des Stundenzeigers.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationMinuteHand"></a>
|
|
<li><b>stationMinuteHand</b><br>
|
|
Art des Minutenzeigers.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationMinuteHandBehavoir"></a>
|
|
<li><b>stationMinuteHandBehavoir</b><br>
|
|
Verhalten des Minutenzeigers.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationSecondHand"></a>
|
|
<li><b>stationSecondHand</b><br>
|
|
Art des Sekundenzeigers.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationSecondHandBehavoir"></a>
|
|
<li><b>stationSecondHandBehavoir</b><br>
|
|
Verhalten des Sekundenzeigers.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="stationStrokeDial"></a>
|
|
<li><b>stationStrokeDial</b><br>
|
|
Auswahl des Ziffernblattes.
|
|
</li>
|
|
<br>
|
|
|
|
</ul>
|
|
<br>
|
|
|
|
<b>Model: Digital</b> <br><br>
|
|
|
|
<ul>
|
|
<a name="digitalColorBackground"></a>
|
|
<li><b>digitalColorBackground</b><br>
|
|
Digitaluhr Hintergrundfarbe.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="digitalColorDigits"></a>
|
|
<li><b>digitalColorDigits</b><br>
|
|
Farbe der Balkenanzeige in einer Digitaluhr.
|
|
</li>
|
|
<br>
|
|
|
|
<a name="digitalDisplayPattern"></a>
|
|
<li><b>digitalDisplayPattern [countdownwatch | staticwatch | stopwatch | text | watch]</b><br>
|
|
Umschaltung der Digitalanzeige zwischen einer Uhr (default), einer Stoppuhr, statischen Zeitanzeige oder Textanzeige.
|
|
Der anzuzeigende Text im Modus Textanzeige kann mit dem Attribut <b>digitalDisplayText</b> definiert werden. <br><br>
|
|
<ul>
|
|
<table>
|
|
<colgroup> <col width=5%> <col width=95%> </colgroup>
|
|
<tr><td> <b>countdownwatch </b> </td><td>: CountDown Stoppuhr </td></tr>
|
|
<tr><td> <b>staticwatch</b> </td><td>: statische Zeitanzeige </td></tr>
|
|
<tr><td> <b>stopwatch</b> </td><td>: Stoppuhr </td></tr>
|
|
<tr><td> <b>text</b> </td><td>: Anzeige eines definierbaren Textes </td></tr>
|
|
<tr><td> <b>watch</b> </td><td>: Uhr </td></tr>
|
|
</table>
|
|
</ul>
|
|
<br>
|
|
<br>
|
|
</li>
|
|
|
|
<a name="digitalDisplayText"></a>
|
|
<li><b>digitalDisplayText</b><br>
|
|
Ist das Attribut "digitalDisplayPattern = text" gesetzt, kann mit "digitalDisplayText" der
|
|
anzuzeigende Text eingestellt werden. Per Default ist "Play" eingestellt. <br>
|
|
Mit der Siebensegmentanzeige können Ziffern, Bindestrich, Unterstrich und die Buchstaben
|
|
A, b, C, d, E, F, H, L, n, o, P, r, t, U und Y angezeigt werden.
|
|
So lassen sich außer Zahlen auch kurze Texte wie „Error“, „HELP“, „run“ oder „PLAY“ anzeigen.
|
|
</li>
|
|
<br>
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
|
=end html_DE
|
|
=cut
|