2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

70_BOTVAC.pm:

add pollingMode
add preferences
use whitespace to separate boundaries
remove style element from cleaning statistics

git-svn-id: https://svn.fhem.de/fhem/trunk@19586 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
vuffiraa 2019-06-09 18:11:55 +00:00
parent 1a9548969f
commit f7b7c3cef2
2 changed files with 167 additions and 77 deletions

View File

@ -1,5 +1,9 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it. # Do not insert empty lines here, update check depends on it.
- feature: 70_BOTVAC: add pollingMode
add preferences
use whitespace to separate boundaries
remove style element from cleaning statistics
- bugfix: 73_AutoShuttersControl: fix litte bugs and change manual drive - bugfix: 73_AutoShuttersControl: fix litte bugs and change manual drive
detection detection
- feature: 49_SSCam: In detailview are buttons provided to open the camera - feature: 49_SSCam: In detailview are buttons provided to open the camera

View File

@ -174,7 +174,7 @@ sub GetStatus($;$) {
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
InternalTimer( gettimeofday() + $interval, "BOTVAC::GetStatus", $hash, 0 ); InternalTimer( gettimeofday() + $interval, "BOTVAC::GetStatus", $hash, 0 );
return if ( AttrVal($name, "disable", 0) == 1 ); return if ( AttrVal($name, "disable", 0) == 1 or ReadingsVal($name,"pollingMode",1) == 0);
# check device availability # check device availability
if (!$update) { if (!$update) {
@ -186,6 +186,7 @@ sub GetStatus($;$) {
push(@successor, ["messages", "getSchedule"]); push(@successor, ["messages", "getSchedule"]);
push(@successor, ["messages", "getGeneralInfo"]) if (GetServiceVersion($hash, "generalInfo") =~ /.*-1/); push(@successor, ["messages", "getGeneralInfo"]) if (GetServiceVersion($hash, "generalInfo") =~ /.*-1/);
push(@successor, ["messages", "getPreferences"]) if (GetServiceVersion($hash, "preferences") ne "");
SendCommand($hash, "messages", "getRobotState", undef, @successor); SendCommand($hash, "messages", "getRobotState", undef, @successor);
} }
@ -265,7 +266,13 @@ sub Set($@) {
$usage .= " dismissCurrentAlert:noArg" if ( ReadingsVal($name, "alert", "") ne "" ); $usage .= " dismissCurrentAlert:noArg" if ( ReadingsVal($name, "alert", "") ne "" );
$usage .= " findMe:noArg" if ( GetServiceVersion($hash, "findMe") eq "basic-1" ); $usage .= " findMe:noArg" if ( GetServiceVersion($hash, "findMe") eq "basic-1" );
$usage .= " startManual:noArg" if ( GetServiceVersion($hash, "manualCleaning") ne "" ); $usage .= " startManual:noArg" if ( GetServiceVersion($hash, "manualCleaning") ne "" );
$usage .= " statusRequest:noArg schedule:on,off syncRobots:noArg"; $usage .= " statusRequest:noArg schedule:on,off syncRobots:noArg pollingMode:on,off";
# preferences
$usage .= " robotSounds:on,off" if ( GetServiceVersion($hash, "preferences") !~ /()|(basic-1)/ );
$usage .= " dirtbinAlertReminderInterval:30,60,90,120,150" if ( GetServiceVersion($hash, "preferences") =~ /(basic-\d)|(advanced-\d)/ );
$usage .= " filterChangeReminderInterval:1,2,3" if ( GetServiceVersion($hash, "preferences") =~ /(basic-\d)|(advanced-\d)/ );
$usage .= " brushChangeReminderInterval:4,5,6,7,8" if ( GetServiceVersion($hash, "preferences") =~ /(basic-\d)|(advanced-\d)/ );
# house cleaning # house cleaning
$usage .= " nextCleaningMode:eco,turbo" if ($houseCleaningSrv =~ /basic-\d/); $usage .= " nextCleaningMode:eco,turbo" if ($houseCleaningSrv =~ /basic-\d/);
@ -308,7 +315,7 @@ sub Set($@) {
my $name = $Boundaries[$i]->{name}; my $name = $Boundaries[$i]->{name};
push @names,$name if (!(grep { $_ eq $name } @names) and ($name ne "")); push @names,$name if (!(grep { $_ eq $name } @names) and ($name ne ""));
} }
my $BoundariesList = @names ? join(",", @names) : "textField"; my $BoundariesList = @names ? "multiple-strict,".join(",", @names) : "textField";
$usage .= " setBoundariesOnFloorplan_0:".$BoundariesList if (ReadingsVal($name, "floorplan_0_id" ,"") ne ""); $usage .= " setBoundariesOnFloorplan_0:".$BoundariesList if (ReadingsVal($name, "floorplan_0_id" ,"") ne "");
$usage .= " setBoundariesOnFloorplan_1:".$BoundariesList if (ReadingsVal($name, "floorplan_1_id" ,"") ne ""); $usage .= " setBoundariesOnFloorplan_1:".$BoundariesList if (ReadingsVal($name, "floorplan_1_id" ,"") ne "");
$usage .= " setBoundariesOnFloorplan_2:".$BoundariesList if (ReadingsVal($name, "floorplan_2_id" ,"") ne ""); $usage .= " setBoundariesOnFloorplan_2:".$BoundariesList if (ReadingsVal($name, "floorplan_2_id" ,"") ne "");
@ -428,7 +435,11 @@ sub Set($@) {
elsif ( $a[1] eq "statusRequest" ) { elsif ( $a[1] eq "statusRequest" ) {
Log3($name, 2, "BOTVAC set $name $arg"); Log3($name, 2, "BOTVAC set $name $arg");
SendCommand( $hash, "messages", "getRobotState", undef, ["messages", "getSchedule"] ); my @successor = ();
push(@successor, ["messages", "getPreferences"]) if (GetServiceVersion($hash, "preferences") ne "");
push(@successor, ["messages", "getSchedule"]);
SendCommand( $hash, "messages", "getRobotState", undef, @successor );
} }
# setRobot # setRobot
@ -516,6 +527,39 @@ sub Set($@) {
StorePassword( $hash, $a[2] ); StorePassword( $hash, $a[2] );
} }
# pollingMode
elsif ( $a[1] eq "pollingMode") {
Log3($name, 4, "BOTVAC set $name $arg");
return "No argument given" if ( !defined( $a[2] ) );
readingsSingleUpdate($hash, "pollingMode", ($a[2] eq "off" ? "0" : "1"), 0);
}
# preferences
elsif ( $a[1] =~ /^(robotSounds|dirtbinAlertReminderInterval|filterChangeReminderInterval|brushChangeReminderInterval)$/) {
my $item = $1;
my %params;
Log3($name, 4, "BOTVAC set $name $arg");
return "No argument given" if ( !defined( $a[2] ) );
foreach my $reading ( keys %{ $hash->{READINGS} } ) {
if ($reading =~ /^pref_(.*)/) {
my $prefName = $1;
$params{$prefName} = ReadingsVal($name, $reading, "null");
$params{$prefName} *= 43200 if ($prefName =~ /ChangeReminderInterval/ and $params{$prefName} =~ /^\d*$/);
}
}
return "No preferences present, execute 'set statusRequest' first." unless (keys %params);
$params{$item} = ($item =~ /ChangeReminderInterval/ && $a[2] =~ /^\d*$/ ? $a[2] * 43200 : $a[2]);
SendCommand( $hash, "messages", "setPreferences", \%params );
}
# return usage hint # return usage hint
else { else {
return $usage; return $usage;
@ -563,7 +607,7 @@ sub Attr(@)
if ($attr_value !~ /^\{.*\}/){ if ($attr_value !~ /^\{.*\}/){
$err = "Invalid value $attr_value for attribute $attr_name. Must be a space separated list of JSON strings."; $err = "Invalid value $attr_value for attribute $attr_name. Must be a space separated list of JSON strings.";
} else { } else {
my @boundaries = split " ",$attr_value; my @boundaries = split(/\s/, $attr_value);
my @areas; my @areas;
if (@boundaries > 1) { if (@boundaries > 1) {
foreach my $area (@boundaries) { foreach my $area (@boundaries) {
@ -745,7 +789,7 @@ sub SendCommand($$;$$@) {
} }
$data .= "}"; $data .= "}";
} }
elsif ($cmd eq "setMapBoundaries" or $cmd eq "getMapBoundaries") { elsif ($cmd eq "setMapBoundaries" or $cmd eq "getMapBoundaries" or $cmd eq "setPreferences") {
if (defined($option) and ref($option) eq "HASH") { if (defined($option) and ref($option) eq "HASH") {
$data .= ",\"params\":{"; $data .= ",\"params\":{";
foreach( keys %$option ) { foreach( keys %$option ) {
@ -755,7 +799,6 @@ sub SendCommand($$;$$@) {
$data .= "}"; $data .= "}";
} }
} }
$data .= "}"; $data .= "}";
my $now = time(); my $now = time();
@ -1022,7 +1065,7 @@ sub ReceiveCommand($$$) {
} }
else { else {
# getRobotState, startCleaning, pauseCleaning, stopCleaning, resumeCleaning, # getRobotState, startCleaning, pauseCleaning, stopCleaning, resumeCleaning,
# sendToBase, setMapBoundaries, getRobotManualCleaningInfo # sendToBase, setMapBoundaries, getRobotManualCleaningInfo, getPreferences
if ( ref($return) eq "HASH" ) { if ( ref($return) eq "HASH" ) {
push(@successor , ["robots", "maps"]) push(@successor , ["robots", "maps"])
if ($cmd eq "setMapBoundaries" or if ($cmd eq "setMapBoundaries" or
@ -1048,6 +1091,16 @@ sub ReceiveCommand($$$) {
readingsBulkUpdateIfChanged($hash, "wlanValidity", "unavailable"); readingsBulkUpdateIfChanged($hash, "wlanValidity", "unavailable");
} }
} }
if ($cmd eq "getPreferences") {
if ( ref($return->{data}) eq "HASH") {
my $data = $return->{data};
foreach my $key (keys %{$return->{data}}) {
my $value = $data->{$key};
$value /= 43200 if ($key =~ /ChangeReminderInterval/ and $value =~ /^[1-9]\d*$/);
readingsBulkUpdateIfChanged($hash, "pref_$key", $value);
}
}
}
if ( ref($return->{cleaning}) eq "HASH" ) { if ( ref($return->{cleaning}) eq "HASH" ) {
my $cleaning = $return->{cleaning}; my $cleaning = $return->{cleaning};
readingsBulkUpdateIfChanged($hash, "cleaningCategory", GetCategoryText($cleaning->{category})); readingsBulkUpdateIfChanged($hash, "cleaningCategory", GetCategoryText($cleaning->{category}));
@ -1298,7 +1351,7 @@ sub GetServiceVersion($$) {
sub SetServices { sub SetServices {
my ($hash, $services) = @_; my ($hash, $services) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $serviceList = join(", ", map { "$_:$services->{$_}" } keys %$services);; my $serviceList = join(", ", map { "$_:$services->{$_}" } keys %$services);
$hash->{SERVICES} = $serviceList if (!defined($hash->{SERVICES}) or $hash->{SERVICES} ne $serviceList); $hash->{SERVICES} = $serviceList if (!defined($hash->{SERVICES}) or $hash->{SERVICES} ne $serviceList);
} }
@ -1660,79 +1713,77 @@ sub GetStatistics($) {
my $model = ReadingsVal($name, "model", ""); my $model = ReadingsVal($name, "model", "");
my $ret = ""; my $ret = "";
$ret .= '<html><head><meta charset="utf-8">'; $ret .= '<html>';
$ret .= '<style>'; $ret .= '<table class="block wide">';
$ret .= ' .botvac tbody {border-top: 1px solid gray; border-bottom: 1px solid gray;}';
$ret .= ' .botvac th, .botvac td {text-align: center; padding-right: 1em;}';
$ret .= ' .botvac caption {text-align: left; padding-bottom: 1em; margin-bottom: 1em;}';
$ret .= '</style>';
$ret .= '</head><body><table class="botvac">';
$ret .= '<caption><b>Report: '.ReadingsVal($name,"name","name").', '.InternalVal($name,"VENDOR","VENDOR").', '.ReadingsVal($name,"model","model").'</b></caption>'; $ret .= '<caption><b>Report: '.ReadingsVal($name,"name","name").', '.InternalVal($name,"VENDOR","VENDOR").', '.ReadingsVal($name,"model","model").'</b></caption>';
$ret .= '<thead>'; $ret .= '<tbody>';
$ret .= '<tr class="col_header">'; $ret .= '<tr class="col_header">';
$ret .= ' <th>Map</th>'; $ret .= ' <td>Map</td><td></td>';
$ret .= ' <th colspan="2">Expected</th>'; $ret .= ' <td colspan="3">Expected</td><td></td>';
$ret .= ' <th>Map</th>'; $ret .= ' <td>Map</td><td></td>';
$ret .= ' <th>Map</th>'; $ret .= ' <td>Map</td><td></td>';
$ret .= ' <th>Charge</th>'; $ret .= ' <td>Charge</td><td></td>';
$ret .= ' <th>Discharge</th>'; $ret .= ' <td>Discharge</td><td></td>';
$ret .= ' <th>Area</th>'; $ret .= ' <td>Area</td><td></td>';
$ret .= ' <th colspan="3">Cleaning</th>'; $ret .= ' <td colspan="5">Cleaning</td><td></td>';
$ret .= ' <th>Charge</th>'; $ret .= ' <td>Charge</td><td></td>';
$ret .= ' <th>Status</th>'; $ret .= ' <td>Status</td><td></td>';
$ret .= ' <th>Date</th>'; $ret .= ' <td>Date</td><td></td>';
$ret .= ' <th>Time</th>'; $ret .= ' <td>Time</td>';
$ret .= '</tr><tr class="col_header">'; $ret .= '</tr><tr class="col_header">';
$ret .= ' <th>No.</th>'; $ret .= ' <td>No.</td><td></td>';
$ret .= ' <th>Area</th>'; $ret .= ' <td>Area</td><td></td>';
$ret .= ' <th>Time</th>'; $ret .= ' <td>Time</td><td></td>';
$ret .= ' <th>Area</th>'; $ret .= ' <td>Area</td><td></td>';
$ret .= ' <th>Time</th>'; $ret .= ' <td>Time</td><td></td>';
$ret .= ' <th>Delta</th>'; $ret .= ' <td>Delta</td><td></td>';
$ret .= ' <th>Speed</th>'; $ret .= ' <td>Speed</td><td></td>';
$ret .= ' <th>Speed</th>'; $ret .= ' <td>Speed</td><td></td>';
$ret .= ' <th>Cat.</th>'; $ret .= ' <td>Cat.</td><td></td>';
$ret .= ' <th>Mode</th>'; $ret .= ' <td>Mode</td><td></td>';
$ret .= ' <th>Freq.</th>'; $ret .= ' <td>Freq.</td><td></td>';
$ret .= ' <th>During</th>'; $ret .= ' <td>During</td><td></td>';
$ret .= ' <th></th><th></th><th></th>'; $ret .= ' <td></td><td></td><td></td><td></td><td></td>';
$ret .= '</tr><tr class="col_header">'; $ret .= '</tr><tr class="col_header">';
$ret .= ' <th></th>'; $ret .= ' <td></td><td></td>';
$ret .= ' <th>qm</th>'; $ret .= ' <td>qm</td><td></td>';
$ret .= ' <th>min</th>'; $ret .= ' <td>min</td><td></td>';
$ret .= ' <th>qm</th>'; $ret .= ' <td>qm</td><td></td>';
$ret .= ' <th>min</th>'; $ret .= ' <td>min</td><td></td>';
$ret .= ' <th>%</th>'; $ret .= ' <td>%</td><td></td>';
$ret .= ' <th>%/min</th>'; $ret .= ' <td>%/min</td><td></td>';
$ret .= ' <th>qm/min</th>'; $ret .= ' <td>qm/min</td><td></td>';
$ret .= ' <th></th><th></th><th></th>'; $ret .= ' <td></td><td></td><td></td><td></td><td></td><td></td>';
$ret .= ' <th>Run</th>'; $ret .= ' <td>Run</td><td></td>';
$ret .= ' <th></th>'; $ret .= ' <td></td><td></td>';
$ret .= ' <th colspan="2">YYYY-MM-DD hh:mm:ss</th>'; $ret .= ' <td>YYYY-MM-DD</td><td></td>';
$ret .= '</tr></thead><tbody>'; $ret .= ' <td>hh:mm:ss</td>';
$ret .= '</tr>';
for (my $i=0;$i<$mapcount;$i++) { for (my $i=0;$i<$mapcount;$i++) {
my $map = \$hash->{helper}{MAPS}[$i]; my $map = \$hash->{helper}{MAPS}[$i];
my $t1 = GetSecondsFromString($$map->{end_at}); my $t1 = GetSecondsFromString($$map->{end_at});
my $t2 = GetSecondsFromString($$map->{start_at}); my $t2 = GetSecondsFromString($$map->{start_at});
my $dt = $t1-$t2-$$map->{time_in_suspended_cleaning}-$$map->{time_in_error}-$$map->{time_in_pause}; my $dt = $t1-$t2-$$map->{time_in_suspended_cleaning}-$$map->{time_in_error}-$$map->{time_in_pause};
my $dc = $$map->{run_charge_at_start}-$$map->{run_charge_at_end}; my $dc = $$map->{run_charge_at_start}-$$map->{run_charge_at_end};
my $expa = int($$map->{cleaned_area}*100/$dc+.5) if ($dc > 0); my $expa = ($dc > 0 ? int($$map->{cleaned_area}*100/$dc+.5) : 0);
my $expt = int($dt*100/$dc/60+.5) if ($dc > 0); my $expt = ($dc > 0 ? int($dt*100/$dc/60+.5) : 0);
$ret .= '<tr class="col_'.($i%2?"even":"odd").'row">'; my($gen_date,$gen_time) = split(" ", GetTimeFromString($$map->{generated_at}));
$ret .= ' <td>'.($i+1).'</td>'; # Map No. $ret .= '<tr class="'.($i%2?"even":"odd").'">';
$ret .= ' <td>'.($expa>0?$expa:0).'</td>'; # Expected Area $ret .= ' <td>'.($i+1).'</td><td> </td>'; # Map No.
$ret .= ' <td>'.($expt>0?$expt:0).'</td>'; # Expected Time $ret .= ' <td>'.($expa>0?$expa:0).'</td><td> </td>'; # Expected Area
$ret .= ' <td>'.int($$map->{cleaned_area}+.5).'</td>'; # Map Area $ret .= ' <td>'.($expt>0?$expt:0).'</td><td> </td>'; # Expected Time
$ret .= ' <td>'.(($dt>0)?(int($dt/60+.5)):0).'</td>'; # Map Time $ret .= ' <td>'.int($$map->{cleaned_area}+.5).'</td><td> </td>'; # Map Area
$ret .= ' <td>'.($dc>0?$dc:0).'</td>'; # Charge Delta $ret .= ' <td>'.(($dt>0)?(int($dt/60+.5)):0).'</td><td> </td>'; # Map Time
$ret .= ' <td>'.(($dt>0 and $dc>0)?(int($dc*600/$dt+.5)/10):0).'</td>'; # Discharge Speed $ret .= ' <td>'.($dc>0?$dc:0).'</td><td> </td>'; # Charge Delta
$ret .= ' <td>'.(($expt>0 and $expa>0)?(int($expa*10/$expt+.5))/10:0).'</td>'; # Area Speed $ret .= ' <td>'.(($dt>0 and $dc>0)?(int($dc*600/$dt+.5)/10):0).'</td><td> </td>'; # Discharge Speed
$ret .= ' <td>'.GetCategoryText($$map->{category}).'</td>'; # Cleaning Category $ret .= ' <td>'.(($expt>0 and $expa>0)?(int($expa*10/$expt+.5))/10:0).'</td><td> </td>'; # Area Speed
$ret .= ' <td>'.GetModeText($$map->{mode}).'</td>'; # Cleaning Mode $ret .= ' <td>'.GetCategoryText($$map->{category}).'</td><td> </td>'; # Cleaning Category
$ret .= ' <td>'.GetModifierText($$map->{modifier}).'</td>'; # Cleaning Frequency $ret .= ' <td>'.GetModeText($$map->{mode}).'</td><td> </td>'; # Cleaning Mode
$ret .= ' <td>'.$$map->{suspended_cleaning_charging_count}.'x</td>'; # Charge During Run $ret .= ' <td>'.GetModifierText($$map->{modifier}).'</td><td> </td>'; # Cleaning Frequency
$ret .= ' <td>'.$$map->{status}.'</td>'; # Status $ret .= ' <td>'.$$map->{suspended_cleaning_charging_count}.'x</td><td> </td>'; # Charge During Run
$ret .= ' <td colspan="2">'.GetTimeFromString($$map->{generated_at}).'</td>'; # Date $ret .= ' <td>'.$$map->{status}.'</td><td> </td>'; # Status
$ret .= ' <td>'.$gen_date.'</td><td> </td>'; # Date
$ret .= ' <td>'.$gen_time.'</td>'; # Time
$ret .= '</tr>'; $ret .= '</tr>';
} }
$ret .= '</tbody></table>'; $ret .= '</tbody></table>';
@ -1748,7 +1799,7 @@ sub GetStatistics($) {
$specification = "Vorwerk VR220(VR300), battery 84 Wh, eco (90 min, 120 qm, power 65 W), turbo (60 min, 90 qm, power 85 W)<br>" if ($model eq "VR220"); $specification = "Vorwerk VR220(VR300), battery 84 Wh, eco (90 min, 120 qm, power 65 W), turbo (60 min, 90 qm, power 85 W)<br>" if ($model eq "VR220");
$ret .= $specification; $ret .= $specification;
$ret .= '</body></html>'; $ret .= '</html>';
return $ret; return $ret;
} }
@ -2250,14 +2301,49 @@ sub wsMasking($$) {
<a name="stop"></a> <a name="stop"></a>
<code> set &lt;name&gt; stop</code> <code> set &lt;name&gt; stop</code>
<br> <br>
stop cleaning and in case of manual cleaning mode close also the websocket connection stop cleaning and in case of manual cleaning mode close also the websocket connection.
</li> </li>
<br> <br>
<li> <li>
<a name="syncRobots"></a> <a name="syncRobots"></a>
<code> set &lt;name&gt; syncRobots</code> <code> set &lt;name&gt; syncRobots</code>
<br> <br>
sync robot data with online account. Useful if one has more then one robot registered sync robot data with online account. Useful if one has more then one robot registered.
</li>
<br>
<li>
<a name="pollingMode"></a>
<code> set &lt;name&gt; pollingMode &lt;1|0&gt;</code>
<br>
set polling on by 1 (default) or off by 0 like attribut disable.
</li>
<br>
<li>
<a name="robotSounds"></a>
<code> set &lt;name&gt; robotSounds &lt;true|false&gt;</code>
<br>
set sounds on by true or off false.
</li>
<br>
<li>
<a name="dirtbinAlertReminderInterval"></a>
<code> set &lt;name&gt; dirtbinAlertReminderInterval &lt;30|60|90|120|150&gt;</code>
<br>
set alert intervall in minutes.
</li>
<br>
<li>
<a name="filterChangeReminderInterval"></a>
<code> set &lt;name&gt; filterChangeReminderInterval &lt;1|2|3&gt;</code>
<br>
set alert intervall in months.
</li>
<br>
<li>
<a name="brushChangeReminderInterval"></a>
<code> set &lt;name&gt; brushChangeReminderInterval &lt;4|5|6|7|8&gt;</code>
<br>
set alert intervall in months.
</li> </li>
<br> <br>
<li> <li>
@ -2311,7 +2397,7 @@ sub wsMasking($$) {
<a name="boundaries"></a> <a name="boundaries"></a>
<code>boundaries</code> <code>boundaries</code>
<br> <br>
Boundary entries separated by space in JSON format, e.g.<br> Boundary entries separated by whitespace in JSON format, e.g.<br>
{"type":"polyline","vertices":[[0.710,0.6217],[0.710,0.6923]],"name":"Bad","color":"#E54B1C","enabled":true}<br> {"type":"polyline","vertices":[[0.710,0.6217],[0.710,0.6923]],"name":"Bad","color":"#E54B1C","enabled":true}<br>
{"type":"polyline","vertices":[[0.7139,0.4101],[0.7135,0.4282],[0.4326,0.3322],[0.4326,0.2533],[0.3931,0.2533], {"type":"polyline","vertices":[[0.7139,0.4101],[0.7135,0.4282],[0.4326,0.3322],[0.4326,0.2533],[0.3931,0.2533],
[0.3931,0.3426],[0.7452,0.4637],[0.7617,0.4196]],"name":"Kueche","color":"#000000","enabled":true}<br> [0.3931,0.3426],[0.7452,0.4637],[0.7617,0.4196]],"name":"Kueche","color":"#000000","enabled":true}<br>