Umsetzung von Befehlen in kaskadierten Skripten sinnvoll??

Hi Leute,
Ich habe in letzter Zeit das Problem, dass Befehle von meinen Remotes über Lua Skripts manchmal gar nicht oder sehr verzögert (bis zu 30-60 Sekunden später) umgesetzt werden!
Kann es eventuell daran liegen, dass Scenen oft verschachtelt aufgerufen werden.
Erklärung:
Ich habe für jeden Raum ein Skript zum Ausschalten. Darin sind 3-10 Geräte die einen Ausschaltebefehl. z.B. “AUS-Küche”

if (fibaro:countScenes()>3) then  fibaro:abort() end -- lösche zuviele Szenen
fibaro:call(228, "turnOff") -- Küche Hauptlicht
fibaro:call(345, "turnOff") -- Küche Neon Arbeitsplatte1
fibaro:call(449, "turnOff") -- Küche Neon Arbeitsplatte2
fibaro:call(617, "turnOff") -- Fibaro Plug Kaffeemaschine
fibaro:debug(os.date("%d.%m.%Y - Küche - AUS"))

Eine weitere Szene deaktiviert bestimmte Bereiche: z.B. “AUS-Unten”

if (fibaro:countScenes()>3) then  fibaro:abort() end -- lösche zuviele Szenen
fibaro:startScene(182); -- AUS Loggia & Terassse
fibaro:startScene(183); -- AUS Wohnzimmer
fibaro:startScene(207); -- AUS Küche
fibaro:call(155, "turnOff"); -- VZ.0
fibaro:call(153, "turnOff"); -- WC.0
fibaro:debug(os.date("%d.%m.%Y - AUS UNTEN"))

Am Ende habe ich ein “Away” Script, welches die 3 Bereiche aufruft:


if (fibaro:countScenes()>3) then  fibaro:abort() end -- lösche zuviele Szenen
fibaro:startScene(176) -- AUS - unten
fibaro:startScene(177) -- AUS - oben
fibaro:startScene(182) -- AUS - Außenbereich

Diese Organisation istv zwar sehr wartungsfreundlich, denn wenn sich in einer Ebene was ändert, brauche ich nicht immer alle Skripte anpassen.
Aber ist sie auch für die zuverlässige Ausführung sinnvoll?
Ist das vielleicht der Grund für verzögerte Auslösung?
Wie habt ihr das organisiert ?

Oder was kann noch der Grund sein ??

Hi pblacky,

könnte eine Überlastung des Z-Wave Netzwerks sein. Je nachdem wieviele Geräte Du hast, wird beim Ausschalten vermutlich einiges los sein.
Du könntest versuchsweise zwischen den Sektionen Wartezeiten einbauen. Oder vielleicht hilft auch explizit vorher abzufragen ob ein Device an ist und es ausgeschaltet werden muss (If…Then…).
Alles reine Vermutung. Meine aber mal was darüber gelesen zu haben.

Danke Andy für den Tipp!
Ja, es sind, wenn ich das ganze Haus abschalte schon so 30-40 Geräte!!
Das mit der Wartezeit ist eine gute Idee, das werd ich mal versuchen. Geht ja recht einfach :wink:

Glaubst du dass durch den Befehl mit der Prüfung wirklich weniger “Traffic” im Z-Wave Netzwerk entsteht?
Ich kann es nicht abschätzen, deshalb wäre eine Möglichkeit toll, den Traffic irgendwie zu messen.
Werde mal etwas im Internet stöbern, vielleicht finde ich dazu was…

So, ich habe nun gleich Nägel mit Köpfen gemacht und ALLES auf einmal umgesetzt.
Mein Skript prüft nun ob die Geräte eingeschaltet sind und schaltet sie aus.

Danach wird (vorsrst zum Test) eine weitere Prüfung gemacht und eine Pushover Nachricht verschickt, sofern ein Gerät den Ausschaltebefehlt nicht umgesetzt hat.
Dieser Teil ist zwar doppelt, aber vorerst für mich OK :wink:
Das alles mit optisch nettem Debug und 200 MS pausen zwischen den Geräten, ich hoffe das ist genug !?!?.

Hier das Skript falls es jemand auch umsetzen möchte.
Über Verbesserungsvorschläge freue ich mich natürlich :wink:

-- 
if (fibaro:countScenes()>3) then  fibaro:abort() end -- lösche zuviele Szenen
Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")) end

DevIDs = {147, 185, 453, 454, 418}

function CheckJal(IDs)
  for i=1, #IDs do
    local DeviceValue = tonumber(fibaro:getValue(IDs[i],"value"))
    local DeviceName   = fibaro:getName(IDs[i])
    local DeviceRoom = fibaro:getRoomNameByDeviceID(IDs[i])
      if (DeviceValue == 1) then
        fibaro:call(IDs[i], "turnOff")
        Debug("green",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." wurde ausgeschaltet")))
        fibaro:sleep(200)
      else
        Debug("grey",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." ist schon AUS")))
    end
  end
end

function RECheckJal(IDs)
  for i=1, #IDs do
    local DeviceValue = tonumber(fibaro:getValue(IDs[i],"value"))
    local DeviceName   = fibaro:getName(IDs[i])
    local DeviceRoom = fibaro:getRoomNameByDeviceID(IDs[i])
    if (DeviceValue == 1) then
      fibaro:setGlobal("PushOver","Fibaro Alarm!,".. DeviceName .. " im Raum: " .. DeviceRoom .. " konnte nicht ausgeschaltet werden..,0,intermission")
      Debug("red",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." wurde nicht ausgeschaltet, Pushover ausgelöst")))
      fibaro:sleep(200)
    end
  end
end

CheckJal(DevIDs)
fibaro:sleep(1000)
RECheckJal(DevIDs)

fibaro:debug(os.date("%d.%m.%Y - Küche - AUS"))

Topp! Und sind die Verzögerungen weg?

Habe das mit den Verzögerungen leider damit noch nicht vollständig lösen können ;-(
Bin da noch auf der Suche…

Aber ich habe das Sktript gestern Nacht noch etwas verfeinert :wink:

--
if (fibaro:countScenes()>3) then  fibaro:abort() end -- lösche zuviele Szenen
Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")) end

DevIDs = {147, 185, 453, 454, 418}

function CheckDev(IDs)
  for i=1, #IDs do
    DeviceValue = tonumber(fibaro:getValue(IDs[i],"value"))
    DeviceName   = fibaro:getName(IDs[i])
    DeviceRoom = fibaro:getRoomNameByDeviceID(IDs[i])
      if (DeviceValue > 0) then
        fibaro:call(IDs[i], "turnOff")
        Debug("green",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." wurde ausgeschaltet")))
        fibaro:sleep(500)
        DeviceValue = tonumber(fibaro:getValue(IDs[i],"value"))
        if (DeviceValue > 0) then
          Debug("red",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." konnte nicht ausgeschaltet werden")))
          fibaro:setGlobal("PushOver","Fibaro Alarm!,".. DeviceName .. " im Raum: " .. DeviceRoom .. " konnte nicht ausgeschaltet werden..,0,intermission")
          fibaro:call(IDs[i], "turnOff")
          fibaro:sleep(200)
        end
      else
        Debug("grey",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." ist schon AUS")))
      end
  end
end
CheckDev(DevIDs)
Debug("white",(os.date("%d.%m.%Y - "..DeviceRoom.." - AUS")))

Tatsache ist, wenn ich auf meinem Remotec Remote (8 fach) zu schnell mehrere Knöpfe drücke oder ein anderes Skript gerade läuft, dann kommt es zu diesen Verzögerungen.
Gestern habe in einem Fall nach fast 30 Sekunden einen Befehlt ausgeführt bekommen ;-(
Das führt natürlich reflexartig zu weiteren drückern auf der Fernbedienung, dann wird es noch schlimmer!!

Ich habe alle meine Fernbedienungs Skripte so programmiert, dass sie über “CentralSceneEvent” laufen und bis zu 6 x gleichzeitig starten können.
Der Gedanke dahinter ist, mehrere Befehle “gleichzeitig” abwickeln zu können.

Eventuell ist das das Problem??

Hi pblacky

Wenn ich deine Beschreibung so durchlese, denke ich es ist keine gute Idee die Szenen >3 zu beenden. Ich würde >1 machen. Nicht dass da was kollidiert. Zumindest mal probieren.

Über die Verzögerungen hab ich im englischen Forum gelesen. Finde den Beitrag leider nicht mehr. Hatte aber was mit Störungen im Z-wave Netz zu tun.

Hi ANdy,
Hab in meinem FERNSTEUER Skript sowohl die auszuführenden Scenen im Skript, als auch die Prüfschleife auf maximal “1” gesetzt:
statt
if (fibaro:countScenes()>3) then fibaro:debug(“zu viele Szenen, gelöscht!!”) fibaro:abort() end
nun
if (fibaro:countScenes()>1) then fibaro:debug(“zu viele Szenen, gelöscht!!”) fibaro:abort() end
seither läuft er schnell und knackig!
Seltsam ist auchm, ich kann die Knöpfe gar nicht so schnell hintereinander drücken dass das Skript die Prüfzeile auslöst, sehr spannend!!
Werd das mal einige Zeit beobschten…

Habe meine Einstellung nun mal einige Zeit beobachtet und leider immer noch keine Lösung gefunden ;-(
Tatsache ist, dass beim Aufruf der AUS Skripte die bis zu 2 weitere Skript Ebene aufrufen von 10 x auslösen ca. 2-3 x eine Verzögerung von mehr als 30 Sekunden bekomme.
Ich überlege mit ernsthaft, dieses “Raum-Skripte” Konzept mit dem kaskadierten Aufrufen der Skripte wieder zu verwerfen!

Nun kommt die Frage nach der Lösung :wink:

Eine Möglichkeit wäre es überall wo ein Raum ausgeschaltet werden solll, eine Schleife einzubauen die alle Geräte abschaltet, so wie in meinem Beispiel:

if (fibaro:countScenes()>1) then fibaro:debug("zu viele Szenen, gelöscht!!") fibaro:abort() end
Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")) end

DevIDs = {151, 302, 153, 155}

function OffDev(IDs)
  local OnCount = 0
  local Counter = 0
  for i=1, #IDs do
    DeviceValue = tonumber(fibaro:getValue(IDs[i],"value"))
    DeviceName = fibaro:getName(IDs[i])
    DeviceRoom = fibaro:getRoomNameByDeviceID(IDs[i])
    Counter = i
    if (DeviceValue > 0) then
      fibaro:call(IDs[i], "turnOff")
      Debug("green",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." wurde ausgeschaltet")))
      OnCount = OnCount+1
      fibaro:sleep(500)
    else
      Debug("grey",(os.date("%d.%m.%Y - "..DeviceRoom.." - "..DeviceName.." ist schon AUS")))
    end
  end
  if (OnCount ~= 0) then
    Debug("yellow",(os.date("%d.%m.%Y - "..OnCount.." von "..Counter.." Geräten wurden ausgeschaltet!" )))
  else
    Debug("grey",(os.date("%d.%m.%Y - alle Geräten - sind bereits AUS.")))
    fibaro:abort()
  end
end
OffDev(DevIDs)

Das hätte aber zur Folge dass bei jeder Erweiterung der Anlage ALLE Skripte die deisen Aufruf haben, geändert werden müssen!
Das gefällt mir eher weniger!

Wie macht ihr das, wenn ihr bestimmte Geräte in einm Raum von mehreren Stellen abschalten wollt??
Mag mich wer inspirieren :wink:

pblacky,

meiner Meinung nach kann das recht strukturiert gelöst werden.
Lege für alle Räume und Device Gruppen Globale Variablen an.
In diesen Variablen speicherst du alle Device ID’s im JSON Format an. (Am Besten mit einem Konfigurations Skript)
Damit brauchst du die Devices nur mehr an einer Stelle managen.
Weitere globale Variablen kannst Du zur Aktionssteuerung verwenden.
Z.B:
Variable SwitchOff.
Im Remotescript befüllst du die Variable mit einem JSON string:
z.B. WZ,VZ,EZ
Die Variable triggert das SwitchOff Skript welches die einzelnen Räume durchgeht(WZ,VZ;EZ) und die zugehörigen Raum Device ID’s lädt.
Nach einlesen der SwitchOff variable wird diese wieder auf “” gesetzt, was einen weiteren Trigger verursacht, aber dieser wird nach Prüfung der Variable abgebrochen.
Dann gehst du durch alle Raumdevices durch und setzt den Status.

Einzig wenn du noch die Devices als trigger brauchst musst du die Scripte anpassen.

Danke @mdietinger für diese Inspiration!!
So was in der Art geistert schon lange durch meinen Kopf, hatte nur die Umsetzung noch nicht so ganz vor Augen.
Werde mal nachdenken, wie ich da starten kann ohne bestehende Dinge zu beeinflussen :wink:

Wie speichere ich die Ids im JSON Format?
Habe damit (noch) keine Erfahrung!
Werde mich mal hier auf die Suche nach Beispielen mit “JSON” machen, falls du Beispiel Links hast, freue ich mich …

Damit kannst du die Device Tabellen in Variablen anlegen:

function globalVar(var,val) 
  local http = net.HTTPClient()
  http:request("http://127.0.0.1:11111/api/globalVariables", {
    options = {
    method = 'POST',
    headers = {},
    data = '{"name":"'..var..'","value":"'..val..'"}',
    timeout = 10000
  },
  success = function(response)
            local result = response.data;
            if response.status == 200 or response.status == 201 then
              fibaro:debug('Status: ' ..response.status.. ' - Variable wurde angelegt')
            else
              fibaro:debug('Error: ' ..response.status.. ' - Zugriff verweigert')
            end
            end,
  error = function(err)
          fibaro:debug('[ERROR] ' .. err)
          end
  })
end

varSensor = 'ROOM_WZ'
local mySensors = {} -- IDs der Sensoren
table.insert(mySensors, 100)
table.insert(mySensors, 200)
table.insert(mySensors, 300)
table.insert(mySensors, 400)

vOUT = json.encode(mySensors)
if (fibaro:getGlobal(varSensor) ~= nil) then
 fibaro:debug('Benötigte Variable ' ..varSensor.. ' erkannt.')
   fibaro:setGlobal(varSensor,'')
  fibaro:setGlobal(varSensor,vOUT)
else
 fibaro:debug('Benötigte Variable ' ..varSensor.. ' NICHT erkannt. Wird erstellt.')
 globalVar(varSensor, vOUT)
end

Und damit kannst sie abfragen:

varSensor = 'ROOM_WZ'
vIN =fibaro:getGlobal(varSensor)
myConfig = json.decode(vIN)

for j=1, 50 do
  if myConfig[j] ~= nil then
    fibaro:debug('ID:' ..myConfig[j])
  end
end

pblacky,

habe die Scripte etwas aufgeräumt und gleich ein praktisches Bsp. wie du dann die Raumvariablen abfragen kannst

Raumgruppen anlegen:

function globalVar(var,val) 
	if (fibaro:getGlobal(var) ~= nil) then
	 fibaro:debug('Benötigte Variable ' ..var.. ' erkannt.')
	   fibaro:setGlobal(var,'')
	  fibaro:setGlobal(var,val)
	else
	  local http = net.HTTPClient()
	  http:request("http://127.0.0.1:11111/api/globalVariables", {
		options = {
		method = 'POST',
		headers = {},
		data = '{"name":"'..var..'","value":"'..val..'"}',
		timeout = 10000
	  },
	  success = function(response)
				local result = response.data;
				if response.status == 200 or response.status == 201 then
				  fibaro:debug('Status: ' ..response.status.. ' - Variable wurde angelegt')
				else
				  fibaro:debug('Error: ' ..response.status.. ' - Zugriff verweigert')
				end
				end,
	  error = function(err)
			  fibaro:debug('[ERROR] ' .. err)
			  end
	  })
	end
end 

varSensor = 'LIGHTS_ROOM_WOHNZIMMER'
local mySensors = {} -- IDs der Sensoren
table.insert(mySensors, 100)
table.insert(mySensors, 102)
table.insert(mySensors, 103)
table.insert(mySensors, 104)
vOUT = json.encode(mySensors)
globalVar(varSensor, vOUT)

varSensor = 'LIGHTS_ROOM_VORZIMMER'
local mySensors = {} -- IDs der Sensoren
table.insert(mySensors, 200)
table.insert(mySensors, 202)
table.insert(mySensors, 203)
table.insert(mySensors, 204)
vOUT = json.encode(mySensors)
globalVar(varSensor, vOUT)

varSensor = 'LIGHTS_ROOM_KUECHE'
local mySensors = {} -- IDs der Sensoren
table.insert(mySensors, 300)
table.insert(mySensors, 302)
table.insert(mySensors, 303)
table.insert(mySensors, 304)
vOUT = json.encode(mySensors)
globalVar(varSensor, vOUT) 

Script um für eine Gruppe von Räumen alle Sensoren durchgeht.

----------------------------------------------------------
local DeviceGroups  = {'LIGHTS_ROOM_WOHNZIMMER', 'LIGHTS_ROOM_VORZIMMER'} 
------------------------------------------------------------
for i = 1,#DeviceGroups do
	vIN =fibaro:getGlobal(DeviceGroups[i])
	IDs = json.decode(vIN)
	for j = 1,#IDs do
		fibaro:debug('TURN ON Group:' ..DeviceGroups[i] ..' - ID:' ..IDs[j])
	end
end	

Sorry für SPAM.
Überarbeitete Version, ist besser strukturiert:

function globalVar(var,val) 
	if (fibaro:getGlobal(var) ~= nil) then
	 fibaro:debug('Benötigte Variable ' ..var.. ' erkannt.')
	   fibaro:setGlobal(var,'')
	  fibaro:setGlobal(var,val)
	else
	  local http = net.HTTPClient()
	  http:request("http://127.0.0.1:11111/api/globalVariables", {
		options = {
		method = 'POST',
		headers = {},
		data = '{"name":"'..var..'","value":"'..val..'"}',
		timeout = 10000
	  },
	  success = function(response)
				local result = response.data;
				if response.status == 200 or response.status == 201 then
				  fibaro:debug('Status: ' ..response.status.. ' - Variable wurde angelegt')
				else
				  fibaro:debug('Error: ' ..response.status.. ' - Zugriff verweigert')
				end
				end,
	  error = function(err)
			  fibaro:debug('[ERROR] ' .. err)
			  end
	  })
	end
end 

local mySensors = {'LIGHTS_ROOM_WOHNZIMMER',100,102,103,104} -- IDs der Sensoren
vOUT = json.encode(mySensors)
globalVar(mySensors[1], vOUT)

local mySensors = {'LIGHTS_ROOM_VORZIMMER',200,202,203,204} -- IDs der Sensoren
vOUT = json.encode(mySensors)
globalVar(varSensor, vOUT)

local mySensors = {'LIGHTS_ROOM_KUECHE',300,302,303,304} -- IDs der Sensoren
vOUT = json.encode(mySensors)
globalVar(varSensor, vOUT) 

Und das auslese Script: (Fängt erst mit 2. Eintrag an (1=Gruppenname)

----------------------------------------------------------
local DeviceGroups  = {'LIGHTS_ROOM_WOHNZIMMER', 'LIGHTS_ROOM_VORZIMMER'} 
------------------------------------------------------------
for i = 1,#DeviceGroups do
	vIN =fibaro:getGlobal(DeviceGroups[i])
	IDs = json.decode(vIN)
	for j = 2,#IDs do
		fibaro:debug('Group:' ..DeviceGroups[i] ..' - ID:' ..IDs[j])
	end
end	

Vorige Version ist getestet, diese muss erst getestet werden, sollte aber funktionieren

Vielen Dank für deine Unterstützung!!
Ich habe gerade begonnen die Skripte für mich zu adaptieren.

Nur zum Verständnis:

Es wird Im ersten Block eine Variable “mySensors” angelegt (Wohnzimmer)
dann für die anderen Räume die Variable “varSensors” ist das Absicht so?
Oder sollte es auch im ersten Block “varSensors” sein?

Habe das Skript mal mit meinen IDs befüllt und bekomme beim Ablauf:
[DEBUG] 11:19:28: 2018-11-30 11:19:28.918264 [ fatal] Unknown exception: /opt/fibaro/FibaroSceneAPI.lua:146: Assertion failed: Expected string

Muss ich die globalen Variablen SELBST anlegen, oder macht das das Skript automatisch?
Sorry falls ich blöde Fragen stelle, aber ich habe die Logic von “JSON” noch nicht ganz verstanden…

Nimm mal die vorige Version.
Die letzte hat noch einen Bug.
Muss ich noch beseitigen. Variablen werden automatisch erstellt.

Pblacky,

hast den Fehler richtig erkannt :slight_smile: (varSensors)
Diese Szene läuft richtig durch:

--[[
%% properties
%% events
%% globals
--]]

function globalVar(var,val) 

	if (fibaro:getGlobal(var) ~= nil) then
       fibaro:debug('Benötigte Variable ' ..var.. ' erkannt.')
       fibaro:setGlobal(var,'')
       fibaro:setGlobal(var,val)
	else
	  local http = net.HTTPClient()
	  http:request("http://127.0.0.1:11111/api/globalVariables", {
		options = {
		method = 'POST',
		headers = {},
		data = '{"name":"'..var..'","value":"'..val..'"}',
		timeout = 10000
	  },
	  success = function(response)
				local result = response.data;
				if response.status == 200 or response.status == 201 then
				  fibaro:debug('Status: ' ..response.status.. ' - Variable wurde angelegt')
				else
				  fibaro:debug('Error: ' ..response.status.. ' - Zugriff verweigert')
				end
				end,
	  error = function(err)
			  fibaro:debug('[ERROR] ' .. err)
			  end
	  })
	end
end 

local mySensors = {'LIGHTS_ROOM_WOHNZIMMER',100,102,103,104} -- IDs der Sensoren
vOUT = json.encode(mySensors)
globalVar(mySensors[1], vOUT)

local mySensors = {'LIGHTS_ROOM_VORZIMMER',200,202,203,204} -- IDs der Sensoren
vOUT = json.encode(mySensors)
globalVar(mySensors[1], vOUT)

local mySensors = {'LIGHTS_ROOM_KUECHE',300,302,303,304} -- IDs der Sensoren
vOUT = json.encode(mySensors)
globalVar(mySensors[1], vOUT) 

Bezüglich JSON.
Im Code wird ein Array angelegt.
Das Array kannst nicht 1:1 in einer Variable ablegen.
Mit jsonencode wird das Array in einer JSON Struktur abgespeichert.
Mit jsondecode wird das ganze wieder zurück in ein Array gespeichert.

Die Funktion globalVar ist nur für die Variablen Verwaltung da.
Sie prüft ob eine Variable existiert und updated oder erzeugt die Variable.
Variablen können nur über einen API Call erzeugt werden.
Wenn alle Variablen schon existieren, wäre es nur ein Einzeiler mit fibaro:setgGlobal …