2012-10-30 04:27:36 +00:00
# $Id: 98_DeviceMonitor.pm $
#
# Copyright (C) 2012 Dennis Gnoyke
#
# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# This library is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself, either Perl version 5.8.7 or,
# at your option, any later version of Perl 5 you may have available.
#
package main ;
use strict ;
use warnings ;
sub DeviceMonitor_Initialize ($)
{
my ( $ hash ) = @ _ ;
$ hash - > { DefFn } = "DeviceMonitor_Define" ;
$ hash - > { UndefFn } = "DeviceMonitor_Undef" ;
$ hash - > { NotifyFn } = "DeviceMonitor_Notify" ;
$ hash - > { GetFn } = "DeviceMonitor_Get" ;
$ hash - > { AttrList } = "disable:0,1" ;
2013-04-25 16:39:42 +00:00
$ hash - > { FW_summaryFn } = "DeviceMonitor_FwFn" ;
$ hash - > { FW_detailFn } = "DeviceMonitor_FwFn" ;
2012-10-30 04:27:36 +00:00
addToAttrList ( "device_timeout" ) ;
}
2013-04-25 16:39:42 +00:00
sub DeviceMonitor_FwFn ($$)
{
my ( $ FW_wname , $ d , $ room , $ pageHash ) = @ _ ; # pageHash is set for summaryFn.
my $ hash = $ defs { $ d } ;
return DeviceMonitor_GetResult ( $ hash - > { NAME } , "dead" , "html" ) ;
}
2012-10-30 04:27:36 +00:00
sub DeviceMonitor_Define ($$)
{
my ( $ hash , $ def ) = @ _ ;
my @ a = split ( "[ \t][ \t]*" , $ def ) ;
my $ u = "wrong syntax: define <name> DeviceMonitor " ;
return $ u if ( int ( @ a ) < 2 ) ;
$ hash - > { CHANGED } [ 0 ] = "DEFINED" ;
$ hash - > { STATE } = "DEFINED" ;
return undef ;
}
sub
DeviceMonitor_Undef ( $$ )
{
my ( $ hash , $ arg ) = @ _ ;
return DeviceMonitor_Remove ( $ hash , "all" ) ;
return undef ;
}
sub DeviceMonitor_Get ($@)
{
#*******************************************************************************
# Purpose: Get some results
# Author : Dennis Gnoyke
# Date : 27.10.2012
# Changes:
# Remarks:
#**************************** Begin of Code *************************************
my ( $ hash , @ a ) = @ _ ;
return "argument is missing" if ( int ( @ a ) != 2 ) ;
my ( $ criteria , $ output ) = split ( "_" , lc ( $ a [ 1 ] ) ) ;
return DeviceMonitor_GetResult ( $ a [ 0 ] , $ criteria , $ output ) ;
#**************************** End of Code *****************************************
}
sub DeviceMonitor_Notify ($$)
{
#*******************************************************************************
# Purpose: Checks for timeout - Notify reacts on triggers fired from the Device
# Author : Dennis Gnoyke
# Date : 21.10.2012
# Changes: 27.10.2012 GN Code optimized, Events reduced
# Remarks: EXPERIMENTAL VERSION !!!!!!!
#
#**************************** Begin of Code *************************************
my ( $ ownhash , $ devhash ) = @ _ ;
my $ devName = $ devhash - > { NAME } ; #Name of the Device which has triggered this event
my $ ownName = $ ownhash - > { NAME } ; #Name of DeviceMonitor
my $ enabled = $ ownhash - > { ENABLED } ; #DeviceMonitor enabled ?
my $ timeoutinterval = 0 ;
my $ devState = "unknown" ;
$ timeoutinterval = AttrVal ( $ devName , "device_timeout" , 0 ) ; #Timeout configured ?
return "" if ( $ timeoutinterval < 1 && ! defined ( $ defs { $ devName } { HEALTH_MONITORED_BY } ) ) ; #Leave NTFY if device is not configured for DeviceMonitor
if ( AttrVal ( $ devName , "disable" , 0 ) > 0 ) { $ timeoutinterval = 0 } ; #Device Enabled ?
if ( AttrVal ( $ ownName , "disable" , 0 ) > 0 ) #DeviceMonitor Enabled ?
{
$ timeoutinterval = 0 ;
$ ownhash - > { STATE } = "DISABLED" ;
}
else
{
$ ownhash - > { STATE } = "ENABLED" ;
}
Log 4 , "'$devName' is now monitored by '$ownName'" if ( ! defined ( $ defs { $ devName } { HEALTH_MONITORED_BY } ) ) ;
$ devhash - > { HEALTH_MONITORED_BY } = $ ownName ;
# Get current HealthState
if ( ! defined ( $ devhash - > { HEALTH_STATE } ) ) { $ devState = "unknown" } else { $ devState = $ devhash - > { HEALTH_STATE } }
if ( $ timeoutinterval < 1 ) #device_timeout set to 0, remove it from monitor
{
DeviceMonitor_Remove ( $ ownName , $ devName ) ;
RemoveInternalTimer ( $ devhash ) ;
}
else
{
if ( $ devState ne "alive" ) { DoTrigger ( $ devName , "health_state: alive" ) } ;
RemoveInternalTimer ( $ devhash ) ;
$ devhash - > { HEALTH_STATE } = "alive" ;
$ devhash - > { HEALTH_TIME } = TimeNow ( ) ;
$ ownhash - > { READINGS } { $ devName } { VAL } = "alive" ;
$ ownhash - > { READINGS } { $ devName } { TIME } = TimeNow ( ) ;
InternalTimer ( gettimeofday ( ) + ( $ timeoutinterval * 60 ) , "DeviceMonitor_Timer" , $ devhash , 0 ) ;
}
return undef ;
#**************************** End of Code *************************************
}
sub DeviceMonitor_Timer ($)
{
#*******************************************************************************
# Purpose: Checks for timeout - Will be called if timeout occured
# Author : Dennis Gnoyke
# Date : 21.10.2012
# Changes: 22.10.2012 GN Typo Death -> Dead
# Remarks:
#
#**************************** Begin of Code *************************************
#set the HEALTH_STATE to "dead" if not already set
my ( $ devhash ) = @ _ ;
my $ ownName = $ devhash - > { HEALTH_MONITORED_BY } ;
my $ devName = $ devhash - > { NAME } ;
if ( AttrVal ( $ devName , "device_timeout" , 0 ) < 1 ) #device_timeout set to 0, remove it from monitor
{
DeviceMonitor_Remove ( $ ownName , $ devName ) ;
}
else
{
DoTrigger ( $ devName , "health_state: dead" ) ;
$ devhash - > { HEALTH_STATE } = "dead" ;
$ devhash - > { HEALTH_TIME } = TimeNow ( ) ;
$ defs { $ ownName } { READINGS } { $ devName } { TIME } = TimeNow ( ) ;
$ defs { $ ownName } { READINGS } { $ devName } { VAL } = "dead" ;
}
RemoveInternalTimer ( $ devhash ) ;
#**************************** End of Code *****************************************
}
sub DeviceMonitor_GetResult ($$$)
{
#*******************************************************************************
# Purpose: Get results from DeviceMonitor readings
# Author : Dennis Gnoyke
# Date : 27.10.2012
# Changes:
# Remarks: $_[0] = DeviceMonitor
# $_[1] = Criteria dead|alive|total
# $_[2] = Output as count|text|html
#**************************** Begin of Code *************************************
my $ hash = $ defs { $ _ [ 0 ] } { READINGS } ;
my $ cnt = 0 ; #counter
my @ result ; #result array
$ result [ 0 ] = "null" ; #default
my $ tmp = "" ; #temp var
foreach my $ readings_name ( sort keys % { $ hash } ) #Loop through Readings
{
my $ val = $ hash - > { $ readings_name } ;
if ( ref ( $ val ) )
{
my $ readings_value = $ val - > { VAL } ;
my $ readings_time = $ val - > { TIME } ;
if ( $ readings_value eq $ _ [ 1 ] ) #value like dead or alive
{
$ result [ "$cnt" ] = $ readings_name . ',' . "has health_state '$readings_value' reported at $readings_time" ;
$ cnt = $ cnt + 1
}
elsif ( $ _ [ 1 ] eq "total" )
{
$ result [ "$cnt" ] = $ readings_name . ',' . "has health_state '$readings_value' reported at $readings_time" ;
$ cnt = $ cnt + 1
}
}
}
if ( $ result [ 0 ] eq "null" )
{
return 0 if ( $ _ [ 2 ] eq "count" ) ;
return "$_[0]: There was no match for your criteria '$_[1]'" if ( $ _ [ 2 ] eq "text" ) ;
return "$_[0]: There was no match for your criteria '$_[1]'" if ( $ _ [ 2 ] eq "html" ) ;
return "$_[0]: Unknown argument $_[2] , syntax is <criteria>_<output> criteria=dead,alive,total output=count,text,html" ;
}
else
{
if ( $ _ [ 2 ] eq "count" ) { return $ cnt }
elsif ( $ _ [ 2 ] eq "text" )
{
foreach ( @ result )
{
my ( $ device , $ value ) = split ( "," , $ _ ) ;
$ tmp . = "Device $device $value\n" ;
}
return $ tmp ;
}
elsif ( $ _ [ 2 ] eq "html" )
{
$ tmp = "<table>\n" ;
foreach ( @ result )
{
my ( $ device , $ value ) = split ( "," , $ _ ) ;
$ tmp . = "<tr><td>Device <a href='/fhem?detail=$device'>$device</a> $value</td></tr>\n" ;
} ;
$ tmp . = "</table></div>" ;
return $ tmp ;
}
else { return "$_[0]: Unknown argument $_[2] , syntax is <criteria>_<output> criteria=dead,alive,total output=count,text,html" }
}
#**************************** End of Code *****************************************
}
sub DeviceMonitor_Remove ($$)
{
#*******************************************************************************
# Purpose: Resets DeviceMonitor readings
# Author : Dennis Gnoyke
# Date : 28.10.2012
# Changes:
# Remarks: $_[0] = DeviceMonitor
# $_[1] = Criteria devicename|all
#
#**************************** Begin of Code *************************************
my $ hash = $ defs { $ _ [ 0 ] } { READINGS } ;
if ( defined ( $ hash - > { $ _ [ 1 ] } ) ) #remove single device from monitor
{
delete $ hash - > { $ _ [ 1 ] } ;
if ( defined ( $ defs { $ _ [ 1 ] } { HEALTH_MONITORED_BY } ) ) { delete $ defs { $ _ [ 1 ] } { HEALTH_MONITORED_BY } } ;
if ( defined ( $ defs { $ _ [ 1 ] } { HEALTH_STATE } ) ) { delete $ defs { $ _ [ 1 ] } { HEALTH_STATE } } ;
if ( defined ( $ defs { $ _ [ 1 ] } { HEALTH_TIME } ) ) { delete $ defs { $ _ [ 1 ] } { HEALTH_TIME } } ;
RemoveInternalTimer ( $ defs { $ _ [ 1 ] } ) ;
Log 4 , "'$_[1]' is no longer monitored by '$_[0]'" ;
}
elsif ( uc ( $ _ [ 1 ] ) eq "ALL" ) #remove all devices from monitor
{
foreach my $ readings_name ( sort keys % { $ hash } ) #Loop through Readings
{
delete $ hash - > { $ readings_name } ;
if ( defined ( $ defs { $ readings_name } { HEALTH_MONITORED_BY } ) ) { delete $ defs { $ readings_name } { HEALTH_MONITORED_BY } } ;
if ( defined ( $ defs { $ readings_name } { HEALTH_STATE } ) ) { delete $ defs { $ readings_name } { HEALTH_STATE } } ;
if ( defined ( $ defs { $ readings_name } { HEALTH_TIME } ) ) { delete $ defs { $ readings_name } { HEALTH_TIME } } ;
RemoveInternalTimer ( $ defs { $ readings_name } ) ;
}
Log 4 , "all devices removed from '$_[0]', please note that devices will appear again if their device_timeout attr is still set and '$_[0]' is defined and enabled!" ;
}
else
{
return "$_[0]: Can`t remove $_[1] check spelling and upper/lower cases" ;
}
#**************************** End of Code *****************************************
}
2012-10-27 09:17:14 +00:00
1 ;