Collectd Plugin #13
2 changed files with 47 additions and 1 deletions
10
README.md
10
README.md
|
@ -40,6 +40,8 @@ Add or adjust the configuration for your collectd’s Python plugin as follows:
|
||||||
<Module collectd_sem6000>
|
<Module collectd_sem6000>
|
||||||
Address "12:34:56:78:90:ab"
|
Address "12:34:56:78:90:ab"
|
||||||
SocketName "FirstSocket"
|
SocketName "FirstSocket"
|
||||||
|
ReadTimeout 30
|
||||||
|
SuspendTime 300
|
||||||
</Module>
|
</Module>
|
||||||
<Module collectd_sem6000>
|
<Module collectd_sem6000>
|
||||||
Address "ab:cd:ef:13:37:42"
|
Address "ab:cd:ef:13:37:42"
|
||||||
|
@ -49,6 +51,14 @@ Add or adjust the configuration for your collectd’s Python plugin as follows:
|
||||||
</Plugin>
|
</Plugin>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`ReadTimeout` and `SuspendTime` control what’s happening when a device is
|
||||||
|
unavailable. If no value could be retrieved for `ReadTimeout` seconds, the
|
||||||
|
plugin does not retry for `SuspendTime` seconds. After that, normal operation
|
||||||
|
is resumed. This procedure ensures that an unreachable device does not block
|
||||||
|
other devices (too often) in the current single-threaded architecture.
|
||||||
|
|
||||||
|
If not specified, `ReadTimeout` is 30 seconds and `SuspendTime` is 5 minutes.
|
||||||
|
|
||||||
Make sure that everything listed in `requirements.txt` is available to the user
|
Make sure that everything listed in `requirements.txt` is available to the user
|
||||||
running collectd.
|
running collectd.
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# vim: noet ts=2 sw=2 sts=2
|
# vim: noet ts=2 sw=2 sts=2
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
import collectd
|
import collectd
|
||||||
|
|
||||||
from sem6000 import SEMSocket
|
from sem6000 import SEMSocket
|
||||||
|
@ -25,6 +26,12 @@ def config_func(cfg):
|
||||||
if key in ['address', 'socketname']:
|
if key in ['address', 'socketname']:
|
||||||
config[key] = value
|
config[key] = value
|
||||||
|
|
||||||
|
if key == 'readtimeout':
|
||||||
|
config['readtimeout'] = int(value)
|
||||||
|
|
||||||
|
if key == 'suspendtime':
|
||||||
|
config['suspendtime'] = int(value)
|
||||||
|
|
||||||
if 'address' not in config.keys():
|
if 'address' not in config.keys():
|
||||||
collectd.error('sem6000: address must be set')
|
collectd.error('sem6000: address must be set')
|
||||||
return
|
return
|
||||||
|
@ -32,7 +39,19 @@ def config_func(cfg):
|
||||||
if 'socketname' not in config.keys():
|
if 'socketname' not in config.keys():
|
||||||
config['socketname'] = config['address'].replace(':', '')
|
config['socketname'] = config['address'].replace(':', '')
|
||||||
|
|
||||||
instances.append( {'config': config, 'socket': None} )
|
if 'readtimeout' not in config.keys():
|
||||||
|
config['readtimeout'] = 30
|
||||||
|
|
||||||
|
if 'suspendtime' not in config.keys():
|
||||||
|
config['suspendtime'] = 300
|
||||||
|
|
||||||
|
instances.append( {
|
||||||
|
'config': config,
|
||||||
|
'socket': None,
|
||||||
|
'suspended': False,
|
||||||
|
'lastsuccess': 0,
|
||||||
|
'resumetime': 0
|
||||||
|
} )
|
||||||
|
|
||||||
def read_func():
|
def read_func():
|
||||||
global instances
|
global instances
|
||||||
|
@ -40,6 +59,14 @@ def read_func():
|
||||||
for inst in instances:
|
for inst in instances:
|
||||||
config = inst['config']
|
config = inst['config']
|
||||||
|
|
||||||
|
if inst['suspended']:
|
||||||
|
if time.time() < inst['resumetime']:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
collectd.info("sem6000: Device {} waking up.".format(config['address']))
|
||||||
|
inst['suspended'] = False
|
||||||
|
inst['lastsuccess'] = time.time()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if inst['socket'] == None:
|
if inst['socket'] == None:
|
||||||
collectd.info("sem6000: Connecting to {}...".format(config['address']))
|
collectd.info("sem6000: Connecting to {}...".format(config['address']))
|
||||||
|
@ -52,6 +79,13 @@ def read_func():
|
||||||
collectd.warning("sem6000: Exception caught: {}".format(e))
|
collectd.warning("sem6000: Exception caught: {}".format(e))
|
||||||
collectd.warning("sem6000: Restarting on next cycle...")
|
collectd.warning("sem6000: Restarting on next cycle...")
|
||||||
|
|
||||||
|
if inst['lastsuccess'] < time.time() - config['readtimeout']:
|
||||||
|
collectd.error("sem6000: no successful communication with {} for {:.1f} seconds. Suspending device for {:.1f} seconds.".format(
|
||||||
|
config['address'], config['readtimeout'], config['suspendtime']))
|
||||||
|
|
||||||
|
inst['suspended'] = True
|
||||||
|
inst['resumetime'] = time.time() + config['suspendtime']
|
||||||
|
|
||||||
if inst['socket'] != None:
|
if inst['socket'] != None:
|
||||||
inst['socket'].disconnect()
|
inst['socket'].disconnect()
|
||||||
inst['socket'] = None
|
inst['socket'] = None
|
||||||
|
@ -61,6 +95,8 @@ def read_func():
|
||||||
if socket != None and socket.voltage != 0:
|
if socket != None and socket.voltage != 0:
|
||||||
collectd.debug("Uploading values for {}".format(socket.mac_address))
|
collectd.debug("Uploading values for {}".format(socket.mac_address))
|
||||||
|
|
||||||
|
inst['lastsuccess'] = time.time()
|
||||||
|
|
||||||
val = collectd.Values(plugin = 'sem6000-{}'.format(config['socketname']))
|
val = collectd.Values(plugin = 'sem6000-{}'.format(config['socketname']))
|
||||||
|
|||||||
|
|
||||||
val.type = 'voltage'
|
val.type = 'voltage'
|
||||||
|
|
Loading…
Reference in a new issue
I'd prefer to use the BT mac instead of a string as plugin name here. There's a good chance we can read the name of the socket over BT and expose it later with this plugin which would allow a mapping even if the name changes.
Are you sure that the name is actually stored on the socket? My feeling is that that’s only a mapping in the app.
I prefer to have a string in the plugin name, because it indicates the purpose of the measurements (which can change as devices are reused). If you don't like it, just copy the address into
SocketName
😉 in the collectd config.