Hi,
ich habe in der myUtils eine sub geschrieben, die anhand unzähliger Parameter eine Entscheidung trifft, ob ein Aktor ein-, oder ausgeschaltet werden soll.
Diese Funktion wird alle 60 Sekunden aufgerufen.
Das funktioniert soweit, jetzt habe ich nur den Wunsch (weil ich als Bediener eh alles besser weiss und kann als die automatik:P) dass ich manuell die Entscheidung übersteuern kann.
Mit dem Befehl "set Aktor on" kann ich den aktor jetzt auch manuell einschalten, sobald die subroutine ausgeführt wird, stellt sie fest, dass die ausschaltbedingung gegeben ist und schaltet den Aktor wieder aus.
Mir fallen auf anhieb einige Lösungsansätze ein (zusätzliche Dummys, Doifs, notifies), aber da erscheint mir eine umständlicher als die andere.
Deshalb wollte ich mal von euch wissen, ob ihr so ein Problem auch schon mal hattet, und wie ihr es gelöst habt (oder lösen würdet).
Danke für euren Input,
Grüße,
Stephan
Du hast dabei immer Grundsätzlich das Problem: Woher weiß die Automatik, das Du sie übersteuerst?
Also wirst Du um ein Zusätzliches Element nicht drum rum kommen ...
Zitat von: Wernieman am 15 März 2018, 10:59:24
Woher weiß die Automatik, das Du sie übersteuerst?
Ja, eben. Aber wie löst man das am geschicktesten, mit wenig Overhead, wenigen zusätzlichen Events ...
Grüße,
Stephan
Zitat von: Wernieman am 15 März 2018, 10:59:24
Du hast dabei immer Grundsätzlich das Problem: Woher weiß die Automatik, das Du sie übersteuerst?
Also wirst Du um ein Zusätzliches Element nicht drum rum kommen ...
Das könnte aber uU. schon vorhanden sein, z.B. das readingsAge() eines auslösenden Tastendrucks (damit könnte man die Automatik für eine gewisse Zeit übergehen oder Prüfen, ob dann wieder manuell ausgeschaltet wurde (Vergleich mit readingsAge einer anderen Taste).
Kommt eben drauf an, was schon vorhanden ist, das solltest du uns dann mitteilen....
Hallo,
habe ich mit einem reading eines Dummy's gelöst in dem die Betriebsart drin steht. Bei mir ist es die Heizung (automatik, manuell, boost, aus). Sobald ich manuell einen Wert eingebe wird auch der dummy auf manuell gestellt. Nachts setze ich alles wieder auf Automatik.
Deine Subroutine sollte dann prüfen ob das reading auf Automatik steht.
Gruß
Eisix
Na ja, das hatte er ja oben schon geschrieben, dass ihm das klar war.
Was evtl. auch ginge: Die routine wird ja irgendwie jede Minute angestupst. Wenn das ein at ist: einfach disable/enable verwenden oder da beim Ein- und Ausschalten ein Attribut o. Reading setzen, das du mit abfragst - das spart wenigstens den dummy...
Zitat von: Eisix am 15 März 2018, 11:23:41
Hallo,
habe ich mit einem reading eines Dummy's gelöst in dem die Betriebsart drin steht. Bei mir ist es die Heizung (automatik, manuell, boost, aus). Sobald ich manuell einen Wert eingebe wird auch der dummy auf manuell gestellt. Nachts setze ich alles wieder auf Automatik.
Deine Subroutine sollte dann prüfen ob das reading auf Automatik steht.
Gruß
Eisix
Bei mir genau das selbe. Dummy anlegen und dann diesen abfragen.
Hi,
ZitatreadingsAge() eines auslösenden Tastendrucks
Innovative Idee! genau solchen Input hatte ich mir erhofft.
ZitatWenn das ein at ist: einfach disable/enable verwenden oder da beim Ein- und Ausschalten ein Attribut o. Reading setzen, das du mit abfragst - das spart wenigstens den dummy...
So hab ichs momentan (quick and dirty) gebaut, allerdings mit einem DOIF anstatt einem AT. Geht auch.
ZitatKommt eben drauf an, was schon vorhanden ist, das solltest du uns dann mitteilen....
Nagut, hier die komplette situation. Möchte aber darauf hinweisen, dass ich nach generischen Lösungsansätzen/ideen suche und keine Schritt-für-schritt-Anleitung für meine persönliche Situation... je nachdem, was mir morgen so einfällt, kann das ganze ganz schnell wieder anders aussehen ::)
Ich habe einen KNX-Aktor, der eine Ladepumpe steuert. mit dieser lade ich heisses wasser von einem in einen anderen Pufferspeicher (ein großer, damit ich die Wärme vom Holzvergaser schnell genug weg schaffe, und ein kleiner für den "täglichen Bedarf (Warmwasser, Solar, Heizung, Gas, usw) als Heizzentrale.
Nun habe ich eine subroutine geschrieben, die mir anhand diverser Bedingungen (erwarteter Solarertrag, erwarteter Energieverbrauch durch Heizung, mindestladung damit ich warmes Wasser habe, Laufzeit des HV, Füllstand des großen Puffers (quasi als Notkühlung, falls ich mich mal vertan hab) entscheidet, ob die Pumpe läuft.
Dann schicke ich aus der sub den Befehl
fhem("set pumpe on")
Hm. Ich könnte ja auch den code posten... warum ist mir das nicht gleich eingefallen .. die Grippe hat doch mehr zerstört, als ich dachte ;P
Hier:
sub move_heat {
my %temps = getHashTemps();
my $HV_VL = ReadingsNum("RE_TEMP_HV_VL","temperature",0);
my $VLtemp = ReadingsNum("RE_TEMP_VorlaufHK","temperature",0);
my $log_name = "move_heat()";
my $subloglevel = 3;
my $previous_loglevel = AttrVal("global","verboseTelegram",0);
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $subloglevel");
}
my $pump3to1 = "off";
my $pump1to3 = "off";
##if($HV_)
## Aussentemperaturgeregelt
my $ps1500_border_sensor;
my $AT = ReadingsNum("RE_TEMP_AUSSEN","temperature",0);
my $value = int(($AT*0.15)+5);
log_telegram("5",$log_name,"Grenze laut AT auf $value","remotebot");
################ Solarprognosengeregelt
my $ertrag = ReadingsNum("wetter_prop","fc0_prg_ges",0);
if($ertrag < 10)
{
$value = 2;
log_telegram("5",$log_name,"Solarertrag $ertrag kWh < 10: Grenze auf $value","remotebot");
}
elsif ($ertrag < 40 && $value < 4)
{
$value = int($ertrag/10);
log_telegram("5",$log_name,"Solarertrag $ertrag kWh < 40: Grenze auf $value","remotebot");
}
elsif ($ertrag > 40)
{
## entscheidung wird nach AT gefällt
log_telegram("5",$log_name,"Solarertrag $ertrag kWh > 40: Grenze auf $value","remotebot");
}
# Grenze mindestens auf 2, damit ich noch Reserve habe.
$value = $value < 3 ? 3:$value;
$value = $value > 8 ? 8:$value;
my $grenzfuehler = $value > 9 ? "15":"150" ;
log_telegram("5",$log_name,"gf: $grenzfuehler","remotebot");
$grenzfuehler .= $value;
log_telegram("5",$log_name,"gf: $grenzfuehler","remotebot");
my $test = $temps{$grenzfuehler+1};
my $test2 = $temps{$grenzfuehler-1};
log_telegram("5",$log_name,"test: $test - $test2","remotebot");
log_telegram("5",$log_name,"Temperatur grenzfühler: $grenzfuehler: $temps{$grenzfuehler}","remotebot");
## Pumpen oder nicht pumpen, das ist hier die Frage
if($temps{'3002'} > 40 && $temps{'1501'} < 40){ ## wenn 3000 unten > 40 und im 1500er ist noch platz
$pump3to1 = "on";
log_telegram("4",$log_name,"1: $temps{'3002'} > 40 && $temps{'1501'} < 40\n Pumpe ein","remotebot");
} elsif ($temps{$grenzfuehler-1} > $VLtemp){ ## Wenn genug Wärme im 1500er ist, Grenze ist variabel
$pump3to1 = "off";
log_telegram("4",$log_name,"2: gf-1: $temps{$grenzfuehler-1} > VLtemp: $VLtemp\n Pumpe aus","remotebot");
log_telegram("5",$log_name,"gf $grenzfuehler","remotebot");
} elsif($temps{$grenzfuehler+1} < $VLtemp){
$pump3to1 = "on";
log_telegram("4",$log_name,"3:gf+1: $temps{$grenzfuehler+1} < VLtemp: $VLtemp\n Pumpe ein","remotebot");
} elsif($temps{'3011'} > $temps{'1509'} && $temps{'3011'} > $temps{'1510'}){
$pump3to1 = "on";
log_telegram("4",$log_name,"4: $temps{'3011'} > $temps{'1510'}\n Pumpe ein","remotebot");
}
## Wenn die Pumpe schon das tut, was sie soll, brauchen wir sie nicht schalten
my $pumpstate = ReadingsVal("KNX02.O08_Aktor_UWP_3000_1500","state",0);
log_telegram("5",$log_name,"pumpstate $pumpstate","remotebot");
if($pumpstate eq $pump3to1){
log_telegram("4",$log_name,"Pumpe ist bereits: _ $pumpstate _, tue nichts.","remotebot");
}else {
log_telegram("3",$log_name,"schalte Pumpe _ $pump3to1 _","remotebot");
fhem("set KNX02.O08_Aktor_UWP_3000_1500 $pump3to1");
}
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $previous_loglevel");
}
}
Da sich subroutinen leider nicht selbst aufrufen können, hab ich das mit einem DOIF alle 60 sekunden getan:
( nur die Kurzfassung, da ich in der zwischenzeit auch ein bisschen rumgebastelt hab :
([+60])({
move_heat();
})
Damit ich sehen kann, ob die Pumpe gerade läuft oder nicht, hab ich mir in der tabletUI ein widget angelegt, welches mir den aktuellen Status von KNX02.O08_Aktor_UWP_3000_1500 anzeigt. Damit ich auch schalten kann, habe ich ein switch-widget angelegt und schalte damit direkt den Aktor.
Da ist natürlich keine Kommunikation zwischen dem DOIF, der sub und mir vorhanden. Mit der "ReadingsAge()" -Idee könnte man zumindest raten, ob der letzte schaltbefehl vor %60 Sekunden kam (also vom PC) oder ich von Hand eingeschaltet habe. Lässt zwar immernoch eine gewisse Wahrscheinlichkeit zu, dass ich genau im richtigen Moment geklickt hab....
Da ich aber bereits des öfteren mit der "mach noch ein dummy, mach noch ein notify" -policy etwas hadere (ich setze z.B. mittlerweile auch die Tasterevents von KNX in einer großen sub um, anstatt für jeden Taster ein eigenes notify zu haben - da habe ich mehrfach den Überblick verloren... ) möchte ich das gerne möglichst einfach lösen.
Am liebsten wäre mir, wenn das in perl ginge. Leider kann man innerhalb der subs keine Variablen speichern, so dass ich ebenfalls bereits darüber nachgedacht habe, ein Device als "Storage" anzulegen und dort benötigte Variablen abzulegen und wieder zu holen. Dagegen spricht, dass keine Gruppierung möglich ist (ausser, mit mehreren Devices) und dass ich nicht weiss, ob ein "ReadingsVal(), rechne was, setreading xy" weniger Rechenintensiv ist als zusätzliche Events durch zusätzliche Devices...
In der Zwischenzeit hab ich mein DOIF wie folgt umgebaut:
Internals:
DEF ([+60] && [$SELF:pump_mode] eq "auto")({
move_heat();
})
DOELSEIF ([$SELF:pump_mode] eq "man_on")
(
set KNX02.O08_Aktor_UWP_3000_1500 on,
setreading $SELF pump_mode man_on
)
(
setreading $SELF pump_mode auto
)
DOELSEIF ([$SELF:pump_mode] eq "man_off")
(
set KNX02.O08_Aktor_UWP_3000_1500 off,
setreading $SELF pump_mode man_off
)
(
setreading $SELF pump_mode auto
)
DOELSEIF ([$SELF:pump_mode] eq "auto")
(
setreading $SELF pump_mode auto
)
NAME DF_Speicher_Umladen
NR 648
NTFY_ORDER 50-DF_Speicher_Umladen
STATE auto
TYPE DOIF
READINGS:
2017-10-24 15:45:35 Pumpe_3000_1500 off
2018-03-15 12:36:59 cmd 1
2018-03-15 12:36:59 cmd_event timer_1
2018-03-15 12:36:59 cmd_nr 1
2018-03-15 11:37:59 mode enabled
2018-03-15 11:38:46 pump_mode auto
2018-03-15 12:36:59 state auto
2018-03-15 12:36:59 timer_01_c01 15.03.2018 12:37:59
2018-03-15 11:39:04 wait_timer no timer
Regex:
condition:
0 DOIF_time_once($hash,0,$wday) && ReadingValDoIf($hash,'DF_Speicher_Umladen','pump_mode') eq "auto"
1 ReadingValDoIf($hash,'DF_Speicher_Umladen','pump_mode') eq "man_on"
2 ReadingValDoIf($hash,'DF_Speicher_Umladen','pump_mode') eq "man_off"
3 ReadingValDoIf($hash,'DF_Speicher_Umladen','pump_mode') eq "auto"
days:
devices:
0 DF_Speicher_Umladen
1 DF_Speicher_Umladen
2 DF_Speicher_Umladen
3 DF_Speicher_Umladen
all DF_Speicher_Umladen
do:
0:
0 { move_heat(); }
1:
0 set KNX02.O08_Aktor_UWP_3000_1500 on, setreading DF_Speicher_Umladen pump_mode man_on
1 setreading DF_Speicher_Umladen pump_mode auto
2:
0 set KNX02.O08_Aktor_UWP_3000_1500 off, setreading DF_Speicher_Umladen pump_mode man_off
1 setreading DF_Speicher_Umladen pump_mode auto
3:
0 setreading DF_Speicher_Umladen pump_mode auto
4:
helper:
DOIF_Readings_events
DOIF_eventas
event timer_1
globalinit 1
last_timer 1
sleepdevice set_cmd_2
sleepsubtimer 1
sleeptimer -1
timerdev
timerevent timer_1
timereventsState
triggerDev
timerevents:
timer_1
triggerEvents:
timer_1
internals:
interval:
itimer:
localtime:
0 1521113879
readings:
0 DF_Speicher_Umladen:pump_mode
1 DF_Speicher_Umladen:pump_mode
2 DF_Speicher_Umladen:pump_mode
3 DF_Speicher_Umladen:pump_mode
all DF_Speicher_Umladen:pump_mode
realtime:
0 12:37:59
time:
0 +60
timeCond:
0 0
timer:
0 0
timers:
0 0
triggertime:
1521113879:
localtime 1521113879
hash:
uiState:
uiTable:
Attributes:
DbLogInclude Pumpe_3000_1500
cmdState auto|an1,an2|aus1,aus2|auto
do always
event-on-change-reading Pumpe_3000_1500
room Heizung,HolzVergaser,_doif
wait 0:0,3600:0,3600:0
widgetOverride cmdState:textField-long
Das ist der (zumindest für diese Situation) einfachste mir bekannte Weg.
Habt ihr Alternativen?
Grüße,
Stephan
Danke für das deutlich mehr an Infos, soviel wäre dann auch wieder nicht erforderlich gewesen; ist halt nicht so lustig zu raten, was denn jetzt an FHEM-Devices vorhanden ist und was die ggf. an Optionen und vorhandenen Infos bieten ;) .
Da du den Aktor direkt schaltest, geht das mit readingsAge eher nicht, es sei denn, du würdest prüfen, ob weniger als 58 sek. durch sind, um dann ein reading "manual" beim Aktor zu setzen (? mit toggle-Funktion).
Grundsätzlich wage ich als Perl-noob zu behaupten, dass ein reading...update() das System deutlich weniger belastet, als Events zu produzieren (mit Attribut oder als set für einen dummy).
Und die Häufigkeit des Durchlaufs deiner Funktion kommt mir auch eher hoch vor, aber das nur nebenbei. Kann nicht sagen, ob das für diesen Anwendungsfall gut ist und gg. einer Reaktion auf (mehrere alternative) Events Aufwand spart.
Interessante Sache jedenfalls!
Beta-User
Zitat von: Beta-User am 15 März 2018, 13:38:25
soviel wäre dann auch wieder nicht erforderlich gewesen;
Da ist jemand nicht zufriedenzustellen :) ;D
Zitat
ist halt nicht so lustig zu raten, was denn jetzt an FHEM-Devices vorhanden ist und was die ggf. an Optionen und vorhandenen Infos bieten ;)
Da hast du recht. Anscheinend kam mein Anliegen dann nicht so richtig raus: ich wollte absichtlich keine "auf meine Situation" angepasste Lösung, sondern Ideen, die Problematik der "viel zu vielen Devices" in den Griff zu kriegen.
Hab z.B. meine KNX-Taster (bisher glaub 48 Stück) nicht mehr über 48 Notifies geschaltet, sondern verwende nur eines, was auf KNX* hört, und entscheide in einer sub, was passieren soll. Damit habe ich viel mehr Flexibilität und Übersicht...
Grüße,
Stephan
Zitat von: abc2006 am 15 März 2018, 13:45:26
Da ist jemand nicht zufriedenzustellen :) ;D
8)
Zitat von: abc2006 am 15 März 2018, 13:45:26
ich wollte absichtlich keine "auf meine Situation" angepasste Lösung, sondern Ideen, die Problematik der "viel zu vielen Devices" in den Griff zu kriegen.
Den Ansatz finde ich auch gut, meine "Kritik" zielte ja nur darauf, dass es einen Unterschied macht, ob man einen Taster verwendet, der Events wirft (und auch ein readingsAge() dazu), um einen Aktor zu schalten, oder ob man - wie sich dann nachträglich rausgestellt hat - den Aktor direkt über die Weboberfläche schaltet. Dann hat man nur die Werte am Aktor, aber auch daraus läßt sich was basteln (siehe letzter Beitrag ;) ).
Zitat von: abc2006 am 15 März 2018, 13:45:26
Hab z.B. meine KNX-Taster (bisher glaub 48 Stück) nicht mehr über 48 Notifies geschaltet, sondern verwende nur eines, was auf KNX* hört, und entscheide in einer sub, was passieren soll. Damit habe ich viel mehr Flexibilität und Übersicht...
Sowas finde ich auch gut. Z.B. meine Rolläden und Fensterkontakte haben teilweise userattr, damit ich bei einem Event von einem der Devices nachsehen kann, ob ein "softgepeertes" anderes Device (sind alles HM-BidCoS-Geräte) auch was tun soll. Dazu reicht ein notify ;) . Bin zwar noch nicht ganz fertig, aber vom Prinzip her ist das viel einfacher als jedes Teil mit einem eigenen notify&co zu versorgen.
Da frage ich übrigens auch ab, ob der jeweilige Rolladenaktor ein "set_.*" mit einem gewissen readingsAge hat, um zu verhindern, dass sich die Funktion selber in einer Endlosschleife triggert...
Zitatob man einen Taster verwendet, der Events wirft (und auch ein readingsAge() dazu), um einen Aktor zu schalten, oder ob man - wie sich dann nachträglich rausgestellt hat - den Aktor direkt über die Weboberfläche schaltet.
Klar macht das einen Unterschied. Aber nichtmal ich selbst weiss, ob ich nicht morgen auf die Idee komme, dass ein Taster an der Wand nicht doch besser ist als so eine Web-Oberfläche. Und wenn ich dann dafür alles umbauen muss ... das meinte ich mit generisch.
Ich kämpfe zum beispiel schon ewig mit der Messung von Wärmeleistung in Flüssigkeiten.
Also: Thermometer VL, Thermometer RL, Durchfluss.
Für den Durchfluss musste ich bereits 4 verschiedene Geräte ausprobieren. Anfangs habe ich die Berechnung der Leistung im Durchfluss-Device vorgenommen. Mit dem Erfolg, dass ich jedes mal alle Erwähnungen umbenennen musste, wenn ich das Device geändert hab. Jetzt gibts ein (zusätzliches) Dummy-Device D_WMZ_Heizung, welches extern gespeist wird, dann userReadings berechnet und abgefragt wird. Dann ists egal, woher die Werte kommen. Hätt ich das nur mal früher gewusst.... :)
Solche Ideen sinds, die mir manchmal fehlen....
Zitat
... userattr, damit ich bei einem Event von einem der Devices nachsehen kann, ob ein "softgepeertes" anderes Device auch was tun soll.
versteh ich grad nicht. Könntest du ja mal posten, wenn du durch bist. Vielleicht kann ich mir ne Anregung holen.
Grüße,
Stephan
Kurzfassung, um das Prinzip zu erläutern:
Jalousie:
define Jalousie_Mitte CUL_HM 2A4820
attr Jalousie_Mitte userattr room_map structexclude WindowContactAssociated WindowContactOnHoldState WindowContactOpenMaxClosed WindowContactTiltedMaxClosed WindowContactTiltedMaxClosed JalousieTurnValue JalousieTurnValue WindowContactTiltedMaxClosed
attr Jalousie_Mitte JalousieTurnValue 3
attr Jalousie_Mitte WindowContactAssociated Terrassentuer_EZ
attr Jalousie_Mitte WindowContactOpenMaxClosed 85
attr Jalousie_Mitte WindowContactTiltedMaxClosed 40
Zugehöriger Fensterkontakt:
define Terrassentuer_EZ CUL_HM 2ADF5C
attr Terrassentuer_EZ userattr ShutterAssociated
attr Terrassentuer_EZ ShutterAssociated Jalousie_Mitte
notify:
define n_Rolladen_Window notify .*(closed|open|tilted)|(Rolladen_.*|Jalousie_.*).(motor:.stop.*|set_.*|motor..down.*) { HM_ShutterUtils_Notify($NAME,$EVENT) }
myUtils-Code (Auszug):
sub HM_ShutterUtils_Notify($$) {
#Als Parameter muss der device-Name sowie der Event übergeben werden
#notify-Definition:
#defmod n_Rolladen_Window notify .*(closed|open|tilted)|(Rolladen_.*|Jalousie_.*).(motor:.stop.*|set_.*|motor..down.*) { HM_ShutterUtils_Notify($NAME,$EVENT) }
my ($dev, $rawEvent) = @_;
#Ein "set" löst zwei Events aus, einmal beim (logischen) Gerät direkt, und dann beim entsprechenden Aktor.
#Wir brauchen nur einen (den ersten).
if ($rawEvent =~ /level:/){
Log3 $dev, 4, "Doppelevent: $rawEvent";
return;
}
#Erst mal prüfen, ob das übergebene device überhaupt existiert
if ($defs{$dev}) {
#Als erstes brauchen wir die Info, welcher Rolladen bzw. welcher Fenster- bzw. Türkontakt
#betroffen sind
my $shutter=$dev;
my $textEvent = "Rollo";
if (AttrVal($shutter,'subType', undef) ne "blindActuator"){
$shutter = AttrVal($dev,'ShutterAssociated',undef);
$textEvent = "Window";
}
my $windowcontact = AttrVal($shutter,'WindowContactAssociated',"none");
my $readingsAge = ReadingsAge($shutter,'WindowContactOnHoldState',60);
if (!$shutter) {}
#Ausfiltern von Selbsttriggern!
elsif ($readingsAge < 2) {
Log3 $dev, 4, "Most likely we are triggering ourself: $dev $rawEvent";
return;
}
else {
#Wir speichern ein paar Infos, damit das nicht zu unübersichtlich wird
my $position = ReadingsVal($shutter,'pct',0);
my $winState = Value($windowcontact);
my $maxPosOpen = AttrVal($shutter,'WindowContactOpenMaxClosed',100)+0.5;
my $maxPosTilted = AttrVal($shutter,'WindowContactTiltedMaxClosed',100)+0.5;
my $turnValue = AttrVal($shutter,'JalousieTurnValue',0);
my $onHoldState = ReadingsVal($shutter,'WindowContactOnHoldState',"none");
my $turnPosOpen = $maxPosOpen+$turnValue;
my $turnPosTilted = $maxPosTilted+$turnValue;
my $targetPosOpen = $maxPosOpen+$turnValue;
my $targetPosTilted = $maxPosTilted+$turnValue;
my $motorReading = ReadingsVal($shutter,'motor',0);
my $event = "none";
my $setPosition = $position;
if($rawEvent =~ /set_/) {
$setPosition = substr $rawEvent, 4, ; #FHEM-Befehl
if ($setPosition eq "on") {$setPosition = 100;}
elsif ($setPosition eq "off") {$setPosition = 0;}
#dann war der Trigger über Tastendruck oder Motor-Bewegung
}
elsif ($motorReading =~ /down/) { $setPosition = -1;}
.....
..