Und noch ein Batterie check scipt

[DEBUG] 18:34:54: {id:36,name:Obergeschoß}
[DEBUG] 18:34:54: {id:37,name:Erdgeschoß}
[DEBUG] 18:34:54: {id:325,name:Außenbereich}

Hallo @jeep,
Ich bin immer wieder erfreut, wenn am Sonntag dein Batteriecheck Skript läuft und micht über die Akkustände informiert!
Nun ist mir aufgefallen, dass es beim Batteriestand in Klammer die Räume mitschickt, was mir super gefällt.

Beim Teil der lange nicht ausgelösten Komponenten wird allerdings KEIN Raum mitgeschickt.
Hat das einen Grund?
Oder könnte man das noch einbauen ?
Hier ein Beispiel

  1. REM.379 SceneMaster (Arbeitszimmer) —88 % OK
  2. REM.381 Wallmote (Arbeitszimmer) ------100 % OK
  3. TK.414.Scharf/Unsch. (Wohnzimmer) -----100 % OK
    Checked at: Sun Dec 10 19:15:33 2017
    24 battery devices were checked.

50 non battery devices checked.

RM.315 (Rauch) not breached since: 3023 hours

Hi @pblacky,

klar kann man das einbauen, keine Ahnung warum ich dass nicht gleich gemacht habe, aber das macht bestimmt Sinn.
Hier ist die neue Version.

Changelog für Version 0.9.3
– Raum im LastBreached Abschnitt hinzugefügt
– Kleinere Kosmetikänderungen

--[[
%% autostart
%% properties
%% globals
--]]

-- file:    Batterystatus.lua 
-- version: 0.9.3
-- purpose: This script checks the batteries and sends reports via 
-- email. Since version 0.6.1 and higher: The script also performs a check on
-- non battery devices and reports all devices marked as dead by HC2.
-- The batterie status is checked daily and several reports per week can be
-- emailed.
-- Due to some limitations in the HC2 with FW less then 4.130, only 980 
-- characters per per e-mail could be sent.
-- For batteries that are almost empty, or a dead device is recognized,
-- a push and/or telegram messages will be sent immediately.
-- Also the status of lastBreached can be checked, so you can easely identify
-- devices whose battery may have been empty for a longer time.
-- A manual check is possible at any time. Simply press the Start button.
-- Copyleft 03-2017 {jeep}

local sourceTrigger = fibaro:getSourceTrigger();
local version   = "0.9.3"
local oldnodeId = nil ;
-- The variables below can be changed by user
local subject   = "Battery and device status";
local userIDs   = {2}     -- mailuser ids
local devpEmail = 25      -- devices per email
local maildays  = {1,4,6} -- 1=Sunday, 2=Monday, 3=Tuesday ...7=Saturday
local pushactiv = true;   -- true - sendpush notification
local teleactiv = true;   -- true - send message via telegram 
local phoneID   = {303}   -- phone IDs for push notification
local checktime = "19:15" -- At this time the script is triggerd
local full      = 100 --between 50 and 100 the battery status is assumed to be good
local warning   = 50  --between 30 and 50 battery is running low
local critical  = 30  --below 30 battery status is asumed as critical
local empty     = 255 --probably a completely empty battery
local nBreacheds= 24  --not Breached since nn hours
local checklBreached = true; -- should lastBreached be checked 

Debug = function ( color, message )
  fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"))
end

local function contains(days, val)
   for i=1,#days do
      if days[i] == val then 
         return true
      end
   end
   return false
end

function sendPush(text)
 if (phoneID[1] ~= nil) then
   for i=1, #phoneID do
      if phoneID[i] ~= nil then
        fibaro:debug('Sent push message to ID ' ..phoneID[i])
        fibaro:call(phoneID[i],'sendPush', text)
      end
   end
 end
end

function sendMail(userIDs,subject,status,m)
 local subject = subject..'-'..m 
 if (userIDs[1] ~= nil) then
  for m=1, #userIDs do
     if userIDs[m] ~= nil then
       fibaro:call(userIDs[m], "sendEmail", subject, status)
     end
  end
  status = ' ';
  print('Mail Nr. '..m.. ' sent.')  
 end
end

function checklastBreached(uxtimeStamp, lbreached)
  xseconds = (uxtimeStamp - lbreached)
  xtime    = (xseconds /60) / 60
  xhours   = math.floor(xtime)
  return xhours
end  

function formatString(name, room)
   slength = string.len(name) + string.len(room)
   dlength = 35 - slength 
   dots    = string.rep ("-", dlength)
   return dots
end  

devices = fibaro:getDevicesId({visible = true, enabled = true, isPlugin =false })
function checkBatteries() 
  uxtimeStamp = os.time(dt);
  status  = '';
  vstatus = '';
  bstatus = ''; 
  local n = 0; -- battery device counter
  local v = 0; -- non battery device counter
  local m = 0; -- mail counter
  local x = 0; -- other devices
  Debug('withe', os.date('%c')..', Version: '.. version );
  for id = 1, #devices do
    local batteryLevel = fibaro:get(devices[id], 'batteryLevel')
    local nodeId       = fibaro:get(devices[id], 'nodeId') 
    local isdead       = fibaro:get(devices[id], 'dead')
    if batteryLevel ~= nil and nodeId ~= nil and batteryLevel ~= '' then
       local name   = fibaro:getName(devices[id]) 
       if oldnodeId ~= nodeId then
          local room = fibaro:getRoomNameByDeviceID(devices[id])
          local sectionID = fibaro:getSectionID(devices[id])
          local lbreached = fibaro:get(devices[id], 'lastBreached')
          if not(room == "unassigned") then
             n = n+1
             if tonumber(batteryLevel) >= warning and tonumber(batteryLevel) <= full then
        		Debug('green', "Battery " ..name..' ('..room..') - Battery: '..batteryLevel..' % OK') 
                dots = formatString(name, room)
                status = status .. n .. ") " ..' '..name..' ('..room..') ' .. dots ..batteryLevel..' % OK\n';
             elseif
               tonumber(batteryLevel) >= critical and tonumber(batteryLevel) <= warning then
               Debug('yellow', "Battery " ..name..' ('..room..') - Battery: '..batteryLevel..' % WARNING') 
               dots = formatString(name, room)  
               status = status .. n .. ") " ..name..' ('..room..') '..dots ..batteryLevel..' % WARNING\n';
             elseif 
               tonumber(batteryLevel) < critical  then 
               Debug('red', "Battery " ..name..' ('..room..') - Battery: '..batteryLevel..' %') 
               if pushactiv then           
                  sendPush('Batterie: '.. name ..' in room '.. room ..' '.. batteryLevel..'%.')
               end
               dots = formatString(name, room)
               status = status .. n .. ") " ..name..' ('..room..') ' .. dots ..batteryLevel..' % CRITICAL\n';
             elseif
               tonumber(batteryLevel) > full or tonumber(batteryLevel) == empty then 
               Debug('red', "Battery " ..name..' ('..room..') - Battery: '..batteryLevel..' % probably empty!') 
               if pushactiv then           
                  sendPush('Batterie: '.. name ..' in room '.. room ..' '.. batteryLevel..'%.')
               end
               dots = formatString(name, room)
               status = status .. n .. ") " ..name..' ('..room..') ' .. dots .. batteryLevel..' % Error\n';
             end
          
             if tonumber(isdead) == 1 then
                Debug('red', "Battery " ..name..' ('..room..') - Device is dead!') 
                status = status .. 'Alert! ' .. name..' ('..room..') - Device is dead \n';
                vstatus = vstatus .. 'Alert! ' .. 'device '.. name ..' - Device is dead! \n';   
                sendPush(name ..' in room '.. room ..' '.. batteryLevel..'%. Device is dead!')
                -- if teleactiv then  --Telegram sender
                --   	fibaro:setGlobal('telegram_text', name.. ' is dead! '.. os.date('%c'))  
                --    fibaro:startScene(61)
                -- end  
              end    
              if lbreached ~= nil and checklBreached and tonumber(lbreached) > 0 then
                 xhours = checklastBreached(uxtimeStamp, lbreached)
                 if xhours > nBreacheds then
                    bstatus = bstatus .. name ..' ('..room..') not breached since: ' ..xhours.. ' hours\n'
                 end
              end    
                              
             if (n % devpEmail == 0) and oldNodeId == nodeID then
                if contains(maildays, weekday) then
                   m = m+1
                   sendMail(userIDs,subject,status,m)
                   fibaro:debug(status)
                   status = ' '
                   fibaro:sleep(500)
                end
             end  
         end 
       end 
       oldnodeId = nodeId
    else
       local dtype = fibaro:getType(devices[id])
       if (dtype == 'virtual_device') or (dtype == 'HC_user') or (dtype == 'iOS_device') then  
          x = x+1 
       else 
          v = v+1 
          local name = fibaro:getName(devices[id])  
          local room = fibaro:getRoomNameByDeviceID(devices[id])
          if tonumber(isdead) == 1 then
             Debug('red', "Device " ..name..' ('..room..') - Device is dead!') 
             vstatus = vstatus .. 'Alert! ' .. 'device '.. name ..' - Device is dead! \n';
             sendPush('Device: '.. name ..' in room '.. room .. ' - is dead!')
          end 
       end 
    end  
    fibaro:sleep(100)
  end  --for
 
  status    = status .. 'Checked at: ' .. os.date('%c') ..'\n'
  status    = status ..n.. ' battery devices were checked.\n' 
  vstatus   = vstatus ..v.. ' non battery devices checked.'
  separator = '------------------------------------------------------------'
  header    = ' Nr)-Device (Room)----------------------Value-Status' 
  Debug('withe', os.date('%c'));
  Debug('withe', separator)
  Debug('withe', header)
  Debug('withe', status)
  Debug('withe', separator)
  Debug('white', vstatus)
  Debug('withe', separator)
  Debug('withe', bstatus)
  Debug('withe', "There are " .. x .." other devices, such as plugins, virtual devices, etc.")
  status = status..separator..'\n'..vstatus..'\n'
  status = status..separator..'\n'..bstatus..'\n'..os.date('%c')
  if contains(maildays, weekday) then
     m = m+1
     sendMail(userIDs,subject,status,m)
     status = ' '; 
  end  
end  -- function

function main()
	local currentDate = os.date("*t");
    local currenthour = string.format("%02d", currentDate.hour) .. ":" .. string.format("%02d", currentDate.min)
    weekday = currentDate.wday
	local startSource = fibaro:getSourceTrigger();
    if currenthour == checktime then
       checkBatteries()
	end
	setTimeout(main, 60*1000)
end
 
if (sourceTrigger["type"] == "autostart") then
    main()
else
    local currentDate = os.date("*t");
    local startSource = fibaro:getSourceTrigger();
    weekday = currentDate.wday
    if (startSource["type"] == "other")	then
       checkBatteries()
    end
end

Na du bist ja schnell, DANKE fürs Umsetzen dieser Idee!
Läuft schon, nun weiß ich endlich wo RM.315 verbaut ist :wink:

Erstmal auch von mir Danke für das tolle Script.

Aber ich habe ein kleines Problem.

Ich musste vor 4 Tagen mein Fibaro Fenster Sensor ersetzen weil die sich weder Inkludieren noch Exkludieren ließ und immer mit einem Kreuz im HC2 markiert wurde.

Das ist jetzt schon der dritte seit innerhalb von 2 Jahren.

Ersetzt habe ich diesen nun mit einen Fenstersensor 2 von Fibaro dieser Sensor wird mir im Script aber nicht angezeigt. Kann es sein das man das script irgendwie rebooten muss. Damit es die neuen Sensoren irgendwie einsammelt. Oder wird der Sensor 2 garnicht erst erfasst?

Als ich so den Text geschrieben habe bin ich selbst drauf gekommen ^^.

Lösung Script neu starten.

Hallo zusammen,

ich bekomme leider keine Mails. Nur die Push auf die hinterlegten IDs.

Kann mir jemand helfen bitte.

Danke gringo

Moin zusammen,

also komisch ist die HC2 schon. Ich hab seit gestern nichts geändert. Heute morgen das Script manuell gestartet und siehe da, Mails kommen an. Zwar nicht komplett, mitten drin hört die Zeile auf, aber immerhin.

Grüße
gringo

Hi Leute,
Habe in den letzten Tagen interessante Erkenntnisse zu Batterien und Devices erlangt, die ich gerne teilen möchte.
Unabhängig davon dass jeeps Skript hervorragend funktioniert, sind die von den Geräten bekanntgegebenen Batteriewerte leider oft unzulänglich!

1.) Hatte unlängst ZWEI NodOn Wandschalter, die plötzlich nicht mehr funktionierten.
Nach genauer Betrachtung war die CR-2032 Batterie schon so leer, dass die Spannung beim Senden auf die Hälfte zusammenbrach!
Trotzdem haben BEIDE Wandschalter über das Skript 100% Akkustand gemeldet.

2.) Da einige Fibaro Türsensoren schon einen Batteriestand von 63% anzeigten, habe ich die Batterien getauscht.
Habe dazu neue Batterien von SAFT gekauft und eingebaut.
Seit nun fast 2 Wochen nach dem Tausch meldet das Skript immer noch bei den beiden NEUEN Batterien 94% Batteriestand.

Ich vermute, dass hier die Geräte der HC2 keine korrekten oder aktuellen Werte schickt.
Die Frage ist nur, wie kann man eine korrekte Übertragung des Batteriestandes auslösen?
Meiner Meinungn nach müsste doch das Auslösen eines NodeInformationFrame dafür ausreichen??
Oder habt ihr andere Erfahrungen?

Ich finde es sehr schade, denn nach meinen Erfahrungen aus der Praxis, kann man noch so ein tolles Skript haben, der Nutzen für die Praxis ist eher überschaubar ;-(

@pblacky
Zu 1. Das Script liest dass aus aus dem Controller aus, was der Sensor bei seinem letzten WakeUp gemeldet hat. Bei vielen Geräten wie Fernbedienungen kann das WakeUp ganz ausgeschaltet sein. Dann bekommst Du immer den Wert der bei der Inclusion gemeldet wurde. Das würde ich mal überprüfen.

Zu 2. Das ist normal, bei 63% würde ich keine Batterien tauschen. Schont die Umwelt und Dein Geldbeutel.? Eventuell hätten die noch Monate funktioniert. Ich hatte schon Sensoren mit unter 15% die immer noch liefen. Aber das Batterie- Thema hatten wir hier schon.

Beim nächsten Abschnitt kann ich Dir Recht geben, da gibt es noch einiges seitens der Hersteller zu tun.
Je öfter das WakeUp desto akurater die Batterie Werte, aber auch schnellere Entladung der Batterie.

Ein NIF wird nur bei der Inclusion verschickt, das ist die Visitenkarte des Geräts und damit teilt es dem Controller seine Klassen mit.
Also hat nichts mit Batteriestand zu tun.

Hoffe für ein wenig Klarheit beigetragen zu haben.

Hi,
tolles Script, mal eine doofe Anfängerfrage, wie finde ich heraus welche UserID ich habe und welche phoneID?
Gruß, Jens

Hi Jens,

unter Configuration->Access Control stehen die Benutzer und mobilen Geräte. Der Adminbenutzer hat meistens die ID 2. Wenn Du Dein mobiles Gerät identifiziert hast, klickst Du mit der rechten Maustaste auf das Häkchen und in dem sich öffnenden Chrome oder FF Menü auf Untersuchen. In der blau hinterlegten Zeile sieht Du so was
“<div class=“checkbox1” id=“div_push_20” onclick=“changeCheckboxGeneral(‘push_20’); changePush(20);”></div>” push_20 bedeutet Dein Handy oder Tablet hat die 20.
Viel Erfolg.

Danke für die Hilfe, habs gefunden. Im Debug Fenster wird das schön angezeigt, aber ich bekomme weder ne Email noch ne Push Nachricht. Muss ich da noch irgendwas weiteres konfigurieren? Ggf. im Router?

Der Haken bei meinem Handy ist natürlich gesetzt bei Configuration >> Access Control

In der Variablen maildays (Zeile 30) kannst Du die Tage einstellen an denen eine Mail kommen soll. Sonst ist nichts weiteres einzustellen.

Achso… super, jetzt klappts. Prima, auch von mir vielen Dank für das Script und den freundlichen Support =)

Gruß, Jens

Ich bekomm jeden Tag Push Nachrichten, obwohl bei in Zeile 30 eine 1 steht.
Eine Mail bekomme ich jetzt wieder nicht. Trotz Update auf 4.160

Grüße
gringo

@gringo1
das steht in Zeile 16 und 17:


-- For batteries that are almost empty, or a dead device is recognized,
-- a push and/or telegram messages will be sent immediately.


Also solange irgendein Gerät im kritischen Bereich ist, gibt es Push Nachrichten, immer.

Wenn bei Dir in Zeile 30 - maildays eine 1 drin steht, heisst dass das Sonntags Mails verschickt werden, aber heute ist Samstag. :wink:

Jo Danke,

ich glaub mir dämmert auch grad wieder, das ich beim manuellen ausführen des Scriptes auch nur an dem Tag eine Mail bekomme der eingestellt ist.

Wer lesen kann ist klar im Vorteil ?

Hallo zusammen,
es ist mal wieder Zeit für ein Update. Richtig, da war doch noch die Frage ob man die Bereiche (z.B Stockwerke) mit ausgeben kann. Ja das geht jetzt. Leider kann ich die Ausgabe nicht sortieren da die Geräte dynamisch eingelesen und sofort ausgegeben werden. Dafür müsste ich das Script komplett umbauen so dass ich erst alles in eine Tabelle einlese und dann sortieren könnte. Wenn jemand keine Bereiche (Sectionen) hat, kann/muss er die Variable checkSection auf ‘false’ setzen.
Und noch etwas. Früher hat Fibaro wenn zuviel Text in der Mail war, die Mail einfach gekürzt. Ich habe jetzt den Eindruck dass wenn die Mail zu viele Zeichen enthält, die gar nicht erst verschickt wird. Ich habe die Anzahl der Geräte mal auf 25 gestellt und diese Mails kamen immer an.
Eine Beschreibung der vom Benutzer definierbaren Variablen gibt’s im angehängten PDF.
Das Script läuft jetzt bei mir seit 1 Woche mit FW 4.160 problemlos.

Changelog für Version 1.1.3
– Neue Funktion getSectionNamebyID
– Neue locale Variable ‘checkSection’
– Jede Menge Codeoptimierungen
– Kleine grafische Statussymbole bei der Ausgabe

--[[
%% autostart
%% properties
%% globals
--]]

-- file:    Batterystatus.lua 
-- version: 1.1.3, released on 09.02.2018
-- purpose: This script checks the batteries and sends reports via 
-- email. Since version 0.6.1 and higher: The script also performs a check on
-- non battery devices and reports all devices marked as dead by HC2.
-- The batterie status is checked daily and several reports per week can be
-- emailed.
-- Due to some limitations in the HC2 with FW less then 4.130, only 980 
-- characters per per e-mail could be sent.
-- For batteries that are almost empty, or a dead device is recognized,
-- a push and/or telegram messages will be sent immediately.
-- Also the status of lastBreached can be checked, so you can easely identify
-- devices whose battery may have been empty for a longer time.
-- If you have added new devices or sections, you should restart the script.
-- A manual check is possible at any time. Simply press the Start button.
-- Copyleft Mar-2017 - 2018 {jeep}

local sourceTrigger = fibaro:getSourceTrigger();
local version   = "1.1.3"
local oldnodeId = nil ;
-- The variables below can be changed by user
local subject   = "Battery and device status";
local userIDs   = {2}     -- mailuser ids
local devpEmail = 25      -- devices per email
local maildays  = {1,4,6} -- 1=Sunday, 2=Monday, 3=Tuesday ...7=Saturday
local pushactiv = true;   -- true - sendpush notification
local teleactiv = true;   -- true - send message via telegram 
local phoneID   = {303}   -- phone IDs for push notification
local checktime = "19:15" -- At this time the script is triggerd
local full      = 100 --between 50 and 100 the battery status is assumed to be good
local warning   = 50  --between 30 and 50 battery is running low
local critical  = 30  --below 30 battery status is asumed as critical
local empty     = 255 --probably a completely empty battery
local nBreacheds= 24  --not Breached since nn hours
local checklBreached = true; -- should lastBreached be checked 
local checkSection   = true; -- if false, the section is not displayed in the debug window.

local Debug = function ( color, message )
  fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span"))
end

local function contains(days, val)
   for i=1,#days do
      if days[i] == val then 
         return true
      end
   end
   return false
end

local function sendPush(text)
 if (phoneID[1] ~= nil) then
   for i=1, #phoneID do
      if phoneID[i] ~= nil then
         fibaro:call(phoneID[i],'sendPush', text)
         -- fibaro:debug('Sent push message to ID ' ..phoneID[i])
      end
   end
 end
end

function sendMail(userIDs,subject,status,m)
  local subject = subject..'-'..m 
  if (userIDs[1] ~= nil) then
    for m=1, #userIDs do
      if userIDs[m] ~= nil then
        fibaro:call(userIDs[m], "sendEmail", subject, status)
      end
   end
   status = ' ';
   print('Mail Nr. '..m.. ' sent.')  
  end
end

local function checklastBreached(uxtimeStamp, lbreached)
  local xseconds = (uxtimeStamp - lbreached)
  local xtime    = (xseconds /60) / 60
  local xhours   = math.floor(xtime)
  return xhours
end  

local function formatString(name, room)
   local slength = string.len(name) + string.len(room)
   local dlength = 35 - slength 
   local dots    = string.rep ("-", dlength)
   return dots
end  

local function getSectionNamebyID(values, sectionNr, sectiontab)
  if checkSection then
     for i=1, values do
        section = sectiontab[i].id 
        if section == sectionNr then
           return 'Bereich-' .. string.sub(sectiontab[i].name,1,4)..','
        end  
     end  
  end  
  return ''
end  
local sym ={warn='\226\154\160\239\184\143', empty='\240\159\147\139', crit='\226\157\151\239\184\143', err='\226\157\140' }
local sectiontab = api.get("/sections")
local values = #sectiontab
local devices = fibaro:getDevicesId({visible = true, enabled = true, isPlugin =false })
local function checkBatteries() 
  uxtimeStamp = os.time(dt);
  status  = '';
  vstatus = '';
  bstatus = ''; 
  local n = 0; -- battery device counter
  local v = 0; -- non battery device counter
  local m = 0; -- mail counter
  local x = 0; -- other devices
  Debug('withe', os.date('%c')..', Version: '.. version );
  for id = 1, #devices do
    local batteryLevel = fibaro:get(devices[id], 'batteryLevel')
    local nodeId       = fibaro:get(devices[id], 'nodeId') 
    local isdead       = fibaro:get(devices[id], 'dead')
    if batteryLevel ~= nil and nodeId ~= nil and batteryLevel ~= '' then
       local name   = fibaro:getName(devices[id]) 
       if oldnodeId ~= nodeId then
          local room = fibaro:getRoomNameByDeviceID(devices[id])
          local sectionID = fibaro:getSectionID(devices[id])
          local lbreached = fibaro:get(devices[id], 'lastBreached')
          local sname = getSectionNamebyID(values, sectionID, sectiontab)
          if not(room == "unassigned") then
             n = n+1
             if tonumber(batteryLevel) >= warning and tonumber(batteryLevel) <= full then
                local dots = formatString(name, room)
                local statusOK = string.format("%s) %s %s, im Raum %s hat %s %s %% OK", n, sname, name, room, dots, batteryLevel)
        	    Debug('green', statusOK)
                status = status .. statusOK ..'\n' 
             elseif
                tonumber(batteryLevel) >= critical and tonumber(batteryLevel) <= warning then
                local dots = formatString(name, room)
                local statuswarn = string.format("%s) %s %s, im Raum %s hat %s %s %% %s", n, sname, name, room, dots, batteryLevel, sym.warn)
                Debug('yellow', statuswarn)	
                status = status .. statuswarn ..'\n' 
             elseif 
                tonumber(batteryLevel) < critical  then 
                local dots = formatString(name, room)
                local statuscritical = string.format("%s) %s %s, im Raum %s hat %s %s %% %s", n, sname, name, room, dots, batteryLevel, sym.crit)	 
                Debug('red', statuscritical)
                if pushactiv then           
                   sendPush(statuscritical)
                end
                status = status .. statuscritical ..'\n'
             elseif
                tonumber(batteryLevel) > full or tonumber(batteryLevel) == empty then 
                local dots = formatString(name, room)
                local statusempty = string.format("%s) %s %s, im Raum %s hat %s %s %% %s", n, sname, name, room, dots, batteryLevel, sym.empty)	  
                Debug('red', statusempty)
                if pushactiv then           
                   sendPush(statusempty)
                end
                status = status .. statusempty..'\n';
             end
          
             if tonumber(isdead) == 1 then
                local dots = formatString(name, room)
                local statusdead = string.format("%s) %s %s, im Raum %s ist tot. %s %s", n, sname, name, room, dots, sym.err)
                Debug('red', statusdead) 
                status = status .. statusdead .. '\n';
                vstatus = vstatus .. statusdead .. '\n';   
                sendPush(statusdead)
                -- if teleactiv then  --Telegram sender
                --   	fibaro:setGlobal('telegram_text', name.. ' is dead! '.. os.date('%c'))  
                --    fibaro:startScene(61)
                -- end  
              end    
              if lbreached ~= nil and checklBreached and tonumber(lbreached) > 0 then
                 local xhours = checklastBreached(uxtimeStamp, lbreached)
                 if xhours > nBreacheds then
                    bstatus = bstatus .. name ..' ('..room..') not breached since: ' ..xhours.. ' hours\n'
                 end
              end    
                              
             if (n % devpEmail == 0) and oldNodeId == nodeID then
                if contains(maildays, weekday) then
                   m = m+1
                   sendMail(userIDs,subject,status,m)
                   fibaro:debug(status)
                   status = ' '
                   fibaro:sleep(500)
                end
             end  
         end 
       end 
       oldnodeId = nodeId
    else
       local dtype = fibaro:getType(devices[id])
       if (dtype == 'virtual_device') or (dtype == 'HC_user') or (dtype == 'iOS_device') then  
          x = x+1 
       else 
          v = v+1 
          local name = fibaro:getName(devices[id])  
          local room = fibaro:getRoomNameByDeviceID(devices[id])
          if tonumber(isdead) == 1 then
             local dots = formatString(name, room)
             local sectionID = fibaro:getSectionID(devices[id])
             local sname = getSectionNamebyID(values, sectionID, sectiontab)
             local statusdead = string.format("%s %s, im Raum %s ist tot! ----%s %s", sname, name, room, dots, sym.err)
             Debug('red', statusdead) 
             vstatus = vstatus .. statusdead .. '\n';
             sendPush(statusdead)
          end 
       end 
    end  
    fibaro:sleep(100)
  end  --for
 
  status    = status .. 'Checked at: ' .. os.date('%c') ..'\n'
  status    = status ..n.. ' battery devices were checked.\n' 
  vstatus   = vstatus ..v.. ' non battery devices checked.'
  separator = '------------------------------------------------------------'
  Debug('withe', os.date('%c'));
  Debug('withe', separator)
  Debug('withe', status)
  Debug('withe', separator)
  Debug('white', vstatus)
  Debug('withe', separator)
  Debug('withe', bstatus)
  Debug('withe', "There are " .. x .." other devices, such as plugins, virtual devices, etc.")
  status = status..separator..'\n'..vstatus..'\n'
  status = status..separator..'\n'..bstatus..'\n'..os.date('%c')
  if contains(maildays, weekday) then
     m = m+1
     sendMail(userIDs,subject,status,m)
     status = ' '; 
  end  
end  -- function

function main()
	local currentDate = os.date("*t");
    local currenthour = string.format("%02d", currentDate.hour) .. ":" .. string.format("%02d", currentDate.min)
    weekday = currentDate.wday
	local startSource = fibaro:getSourceTrigger();
    if currenthour == checktime then
       checkBatteries()
	end
	setTimeout(main, 60*1000)
end
 
if (sourceTrigger["type"] == "autostart") then
    main()
else
    local currentDate = os.date("*t");
    local startSource = fibaro:getSourceTrigger();
    weekday = currentDate.wday
    if (startSource["type"] == "other")	then
       checkBatteries()
    end
end

Danke @Jeep für die neue Version