Kleine LUA Scripte Teil 1: Batterie-Check

Habe noch eine Frage zu dem Thema, habe ein Skript (auch von hier übernommen). Auf der Oberfläche der HC2 kommt folgendes zurück:

[DEBUG] 13:39:29: ------------------------------------------------------------
[DEBUG] 13:39:29: 1) WasserSensorWaschr (Waschraum) - Batterie: 76 % OK
[DEBUG] 13:39:29: 2) WasserSensorTechnikr (Technikraum) - Batterie: 54 % OK
[DEBUG] 13:39:29: 3) Beweg_Diele (Diele) - Batterie: 100 % OK
[DEBUG] 13:39:29: 4) Rauchmeld_Wohnzimmer (Wohnzimmer) - Batterie: 100 % OK
[DEBUG] 13:39:29: 5) Rauchmelder_Technikr (Technikraum) - Batterie: 100 % OK
[DEBUG] 13:39:29: 6) ThermostatGBad (GästeBad) - Batterie: 68 % OK
[DEBUG] 13:39:29: 7) Beweg_Vorraum (Vorraum) - Batterie: 81 % OK
[DEBUG] 13:39:29: 8) TempBad (Bad) - Batterie: 100 % OK
[DEBUG] 13:39:29: 9) Beweg_Empore (Empore) - Batterie: 100 % OK
[DEBUG] 13:39:29: 10) Temp_Gästezimmer (Gästezimmer) - Batterie: 67 % OK
[DEBUG] 13:39:29: 11) ButtonWohnz (Wohnzimmer) - Batterie: 100 % OK
[DEBUG] 13:39:29: 12) ButtonSchlafzimmer (Schlafzimmer) - Batterie: 90 % OK
[DEBUG] 13:39:29: 13) Fenster_Gästezimmer (Gästezimmer) - Batterie: 100 % OK
[DEBUG] 13:39:29: 14) Rauchmeld_Waschraum (Waschraum) - Batterie: 100 % OK
[DEBUG] 13:39:29: 15) Button_Hobbyraum (Hobbyraum) - Batterie: 100 % OK
[DEBUG] 13:39:29: 16) Fenster_Hobbyraum (Hobbyraum) - Batterie: 100 % OK
[DEBUG] 13:39:29: 17) Rauchmeld_Kind (Kinderzimmer) - Batterie: 100 % OK
[DEBUG] 13:39:29: 18) Fenster_Waschraum (Waschraum) - Batterie: 100 % OK
[DEBUG] 13:39:29: 19) Fenster_Abstellkamme (Abstellkammer) - Batterie: 100 % OK
[DEBUG] 13:39:29: 20) Fenster_Gästebad (GästeBad) - Batterie: 100 % OK
[DEBUG] 13:39:29: Am :Mon Jun 19 13:39:29 2017
[DEBUG] 13:39:29: Gecheckt wurden 20 devices

in der Email kommt aber folgendes:

1) WasserSensorWaschr (Waschraum) - Batterie: 76 % OK
2) WasserSensorTechnikr (Technikraum) - Batterie: 54 % OK
3) Beweg_Diele (Diele) - Batterie: 100 % OK
4) Rauchmeld_Wohnzimmer (Wohnzimmer) - Batterie: 100 % OK
5) Rauchmelder_Technikr (Technikraum) - Batterie: 100 % OK
6) ThermostatGBad (GästeBad) - Batterie: 68 % OK
7) Beweg_Vorraum (Vorraum) - Batterie: 81 % OK
8) TempBad (Bad) - Batterie: 100 % OK
9) Beweg_Empore (Empore) - Batterie: 100 % OK
10) Temp_Gästezimmer (Gästezimmer) - Batterie: 67 % OK
11) ButtonWohnz (Wohnzimmer) - Batterie: 100 % OK
12) ButtonSchlafzimmer (Schlafzimmer) - Batterie: 90 % OK
13) Fenster_Gästezimmer (Gästezimmer) - Batterie: 100 % OK
14) Rauchmeld_Waschraum (Waschraum) - Batterie: 100 % OK
15) Button_Hobbyraum (Hobbyraum) - Batterie: 100 % OK
16) Fenster_Hobbyraum (Hobbyraum) - Batterie: 100 % OK
17) Rauchmeld_Kind (Kinderzimmer) - Batterie: 100 % OK
18) Fenster_Waschraum (Waschraum) - Batterie: 100 % OK
19) Fenster_Abstellk

An was könnte das liegen das es plötzlich abgeschnitten ist bei 19)

Anbei der Code:

--[[
%% autostart
%% properties
%% globals
--]]
 
-- file: Batteriestatus.lua 
-- Batteriestatus checken und mailen
-- Copyleft 03-2017 {jeep}
 
local sourceTrigger = fibaro:getSourceTrigger();
local oldnodeId = nil ;
local status = ' ' ;
local n = 0;
local subject = "Batterien Status";
local userId  = 2,137
Debug = function ( color, message )
  fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"))
end
 
devices = fibaro:getDevicesId({interfaces = {"battery"}, visible = true, enabled = true})
--print(json.encode(devices))
 
function checkBatteries()
  Debug('withe', os.date('%c'));
  for id = 1, #devices do 
    local batteryLevel = fibaro:get(devices[id], 'batteryLevel')
    local nodeId       = fibaro:get(devices[id], 'nodeId')   
       if batteryLevel ~= nil and nodeId ~= nil
       then 
       local name   = fibaro:getName(devices[id]) 
       if oldnodeId ~= nodeId then
          local room = fibaro:getRoomNameByDeviceID(devices[id]) 
          if not(room == "unassigned") then
             n = n+1
      	     if tonumber(batteryLevel) >= 50 and tonumber(batteryLevel) <=100 then
        		Debug('green', "Batterie " ..name..' ('..room..') - Batterie: '..batteryLevel..' % OK') 
                status = status .. n .. ") " ..name..' ('..room..') - Batterie: '..batteryLevel..' % OK\n';
             elseif
               tonumber(batteryLevel) >= 25 and tonumber(batteryLevel) <= 50 then
               Debug('yellow', "Batterie " ..name..' ('..room..') - Batterie: '..batteryLevel..' % Warnung') 
               status = status .. n .. ") " ..name..' ('..room..') - Batterie: '..batteryLevel..' % Warnung\n';
             elseif 
               tonumber(batteryLevel) < 25  then 
               Debug('red', "Batterie " ..name..' ('..room..') - Batterie: '..batteryLevel..' % Kritisch') 
               status = status .. n .. ") " ..name..' ('..room..') - Batterie: '..batteryLevel..' % Kritisch\n';
             elseif
               tonumber(batteryLevel) > 100  then 
               Debug('red', "Batterie " ..name..' ('..room..') - Batterie: '..batteryLevel..' % vermutlich leer!') 
               status = status .. n .. ") " ..name..' ('..room..') - Batterie: '..batteryLevel..' % Fehler\n';
             end
          end 
       end
       oldnodeId = nodeId
     end
  end 
status = status .. 'Am :' .. os.date('%c') ..'\n'
status = status .. 'Gecheckt wurden ' ..n.. ' devices.' 
 
Debug('withe', os.date('%c'));
Debug('withe', '------------------------------------------------------------')
Debug('withe', status)
 
fibaro:call(userId, "sendEmail", subject, status)
--fibaro:call(5, "sendEmail", subject, status)
end  
 
function main()
    local currentDate = os.date("*t");
    local currenthour = string.format("%02d", currentDate.hour) .. ":" .. string.format("%02d", currentDate.min)
    local weekday     = currentDate.wday
    local startSource = fibaro:getSourceTrigger();
    if ((weekday == 1) and currenthour == "18:00") then
	checkBatteries()
    end
    setTimeout(main, 60*1000)
end
 
if (sourceTrigger["type"] == "autostart") then
   main()
else
	local currentDate = os.date("*t");
	local startSource = fibaro:getSourceTrigger();
	if (startSource["type"] == "other")	then
	   checkBatteries()
	end
 
end

https://www.siio.de/board/thema/und-noch-ein-batterie-check-scipt/page/3/

So, ich bin ein wenig schlauer. Über das Notification Panel, konnte ich Mails mit 1200 Zeichen verschicken, (also ist der Fibaro Server unschuldig), über das Batterie Check Script ist bei 980 Zeichen Schluß. Zwei Sachen fallen mir dazu ein. Entweder es ist eine LUA Begrenzung, aber nicht in der Variable, denn die ist im Debug-Fenster mit 1200 Zeichen gefüllt. Oder, was ich aber unschön fände, ich könnte das Script so umbauen das es z.B. ab 25 devices eine zweite und dritte Mail verschickt. Bekanntlich werden Variablen in LUA nicht explizit deklariert und sind typenlos. Da komm ich so nicht weiter. Ich bleibe auf jedem Fall dran, vielleicht finde ich die eine Lösung.

Zitat von User @jeep aus dem oben geposteten Thread.

Hallo,
habe das Skript kopiert, leider bringt er mir eine Fehlermeldung: line 35: attempt to compare nil with number.
Bin Anfänger, was habe ich falsch gemacht?
Grüße

Hi,
Welches Script genau hast du kopiert?

Viele Grüße Hoggle

@Andre_Soe

(

An was könnte das liegen das es plötzlich abgeschnitten ist bei 19)
)

Du hast das initial Script verwendet, das letzte was auch mehr macht als nur Batterien checken findest Du hier.
(https://www.siio.de/board/thema/und-noch-ein-batterie-check-scipt/page/7/#post-79063)
Dass verschickt auch mehrere Mails.

Hi Travelerpix, hi Hoggle,
gibt es schon eine Antwort zum Hinweis: “Fehlermeldung: line 35: attempt to compare nil with number.”?

Ich habe das Problem auch! Eigentlich müsste doch Zeile 28 (“if batteryLevel ~= nil”) dafür sorgen, dass das Programm bei “nil” gar nicht an diese Stelle kommt!
Ich hätte da gerne mal einen Tipp!

Hi,

ich weiß nicht, wie Deine Zeile 35 oder 34 aussieht.
Inn dem Script oben auf dieser Seite ist Zeile 35 " n = n+1" - da wird nichts verglichen. Das kann es also nicht sein.

Das „if batteryLevel ~= nil" bezieht sich nicht auf alles, sondern nur die Var batteryLevel, aber die steht nicht in Zeile 35…

VG Hoggle

Hi Hoggle,
es steht im 1. Thread, Zeile 35: (https://www.siio.de/board/thema/kleine-lua-scripte-teil-1-batterie-check/) -einfach 1 Seite zurück; ich beziehe mich auf dieses Statement:
“if tonumber(batteryLevel) <= minBatteryLevel then”
Davor steht aber “if batteryLevel ~= nil” (in Zeiel 28). Daraus schließe ich, dass es nicht vorkommen kann, mit “nil” in Zeile 35 zu gelingen, was dann diesen Fehler auslöst (“attempt to compare nil with number”).

… es sei denn, dass …
und genau das verstehe ich nicht: könnte es da Ausnahmen geben; was bedeutet “~=” exakt? Gibt es es eine Syntaxbeschreibung?

Vielleicht schüttelt ja jemand die Lösung aus dem Ärmel; falls nicht werde ich es schon irgendwie herausfinden - ist aber ggf. umständlich.

Hi,

„~=“ bedeutet schon “ungleich” bzw. “nicht gleich”

Denen einen Wert wandelst Du per tonumber um.
Du kannst versuchen auch den zweiten Wert (minBatteryLevel ) per tonumber “gleich” zu machen.

VG Hoggle

@Monti

warum probierst Du nicht mal dieses wesentlich erweiterte und überarbeitete Script. Das läuft bei vielen hier ohne Probleme.
(https://www.siio.de/board/thema/und-noch-ein-batterie-check-scipt/page/7/#post-79063) Version 0.9.1

@Jeep,

jupp - das Script läuft - danke für den Hinweis!

Warum die Abfrage “if batteryLevel ~= nil” den Wert/bzw. NICHT-Wert “nil” durchlässt, werde ich mir noch einmal gesondert ansehen (ich kann LUA zwar lesen und nachvollziehen, aber zum Verstehen muss ich mir mal die Syntax danebenlegen).

Beim Batterie-Check entsteht “nil”, wenn ein Objekt nicht vorhanden ist (es ist neben “0” und “1” quasi der 3. Zustand eines Bit: es ist “nicht vorhanden”). Eine Umwandlung mit tonumber dürfte nicht funktionieren, da … (muss ich erst einmal nachlesen/probieren - ist bis dahin eine Vermutung). In älteren Programmiersprachen gab es diese “Schutzeinrichtung” nicht und ein Programm erzeugte einen Crash, wenn ein Zugriff auf einen nicht allokierten Speicherbereich erfolgte.
Allerdings kenne ich auch andere Sprachen, die mit dem “Nichtvorhandensein” von Variablen ihre Probleme haben.

Aber dennoch danke für die schnellen Reaktionen!