Révision 7e48a2c8
hue: use perlpod and other small changes
| plugins/hue/hue | ||
|---|---|---|
| 1 |
#!/usr/bin/python3 -tt |
|
| 2 |
# -*- coding: utf-8 -*- |
|
| 1 |
#!/usr/bin/env python3 |
|
| 3 | 2 |
|
| 4 |
"""Munin plugin to read various data from Philips Hue. |
|
| 3 |
"""Munin plugin to read various data from Philips Hue devices.
|
|
| 5 | 4 |
|
| 6 |
Copyright 2019, Kim B. Heino, b@bbbs.net, Foobar Oy |
|
| 7 |
License GPLv2+ |
|
| 5 |
=head1 NAME |
|
| 8 | 6 |
|
| 9 |
Munin configuration:
|
|
| 7 |
hue - monitor various data from Philips Hue devices
|
|
| 10 | 8 |
|
| 11 |
[hue] |
|
| 12 |
env.host hue-bridge-ip-or-hostname |
|
| 13 |
env.auth auth-key |
|
| 9 |
=head1 APPLICABLE SYSTEMS |
|
| 10 |
|
|
| 11 |
Homes with Philips Hue light bulbs and motion sensors. |
|
| 12 |
|
|
| 13 |
=head1 CONFIGURATION |
|
| 14 |
|
|
| 15 |
Following config is needed: |
|
| 16 |
|
|
| 17 |
[hue] |
|
| 18 |
env.host hue-bridge-ip-or-hostname |
|
| 19 |
env.auth auth-key |
|
| 20 |
|
|
| 21 |
=head1 AUTHOR |
|
| 22 |
|
|
| 23 |
Kim B. Heino <b@bbbs.net> |
|
| 24 |
|
|
| 25 |
=head1 LICENSE |
|
| 26 |
|
|
| 27 |
GPLv2 |
|
| 28 |
=cut |
|
| 14 | 29 |
""" |
| 15 | 30 |
|
| 31 |
import json |
|
| 16 | 32 |
import os |
| 17 | 33 |
import sys |
| 18 | 34 |
import unicodedata |
| 19 |
import requests |
|
| 35 |
import urllib.request |
|
| 36 |
|
|
| 20 | 37 |
|
| 38 |
def safename(name): |
|
| 39 |
"""Return safe variable name.""" |
|
| 40 |
# Convert ä->a as isalpha('ä') is true
|
|
| 41 |
value = unicodedata.normalize('NFKD', name)
|
|
| 42 |
value = value.encode('ASCII', 'ignore').decode('utf-8')
|
|
| 21 | 43 |
|
| 22 |
def cleanup(value): |
|
| 23 |
"""Convert value to Munin key.""" |
|
| 24 |
ret = [] |
|
| 25 |
for char in value: |
|
| 26 |
if 'a' <= char <= 'z' or '0' <= char <= '9': |
|
| 27 |
ret.append(char) |
|
| 28 |
elif 'A' <= char <= 'Z': |
|
| 29 |
ret.append(char.lower()) |
|
| 30 |
else: |
|
| 31 |
ret.append('_')
|
|
| 32 |
return ''.join(ret) |
|
| 44 |
# Remove non-alphanumeric chars |
|
| 45 |
return ''.join(char.lower() if char.isalnum() else '_' for char in value) |
|
| 33 | 46 |
|
| 34 | 47 |
|
| 35 | 48 |
def sensor_name(data, sensor): |
| ... | ... | |
| 40 | 53 |
if item.get('uniqueid', '').startswith(uniqueid):
|
| 41 | 54 |
name = item['name'] |
| 42 | 55 |
break |
| 43 |
|
|
| 44 |
# Convert ä to a and return it as utf8 string, py2/3 compatible way |
|
| 45 |
name = unicodedata.normalize('NFKD', name)
|
|
| 46 |
return name.encode('ASCII', 'ignore').decode('utf-8')
|
|
| 56 |
return name |
|
| 47 | 57 |
|
| 48 | 58 |
|
| 49 | 59 |
def print_temperatures(data, config, both): |
| 50 |
"""Temperature sensors."""
|
|
| 60 |
"""Motion sensor has temperature sensor - Read it's value."""
|
|
| 51 | 61 |
if not any([sensor['type'] == 'ZLLTemperature' |
| 52 | 62 |
for sensor in data['sensors'].values()]): |
| 53 | 63 |
return |
| ... | ... | |
| 62 | 72 |
for sensor in data['sensors'].values(): |
| 63 | 73 |
if sensor['type'] != 'ZLLTemperature': |
| 64 | 74 |
continue |
| 65 |
label = cleanup(sensor['name'])
|
|
| 75 |
label = safename(sensor['name'])
|
|
| 66 | 76 |
if config: |
| 67 | 77 |
print('{}.label {}'.format(label, sensor_name(data, sensor)))
|
| 68 | 78 |
if not config or both: |
| ... | ... | |
| 71 | 81 |
|
| 72 | 82 |
|
| 73 | 83 |
def print_light_levels(data, config, both): |
| 74 |
"""Light level sensors."""
|
|
| 84 |
"""Motion sensor has light level sensor - Read it's value."""
|
|
| 75 | 85 |
if not any([sensor['type'] == 'ZLLLightLevel' |
| 76 | 86 |
for sensor in data['sensors'].values()]): |
| 77 | 87 |
return |
| ... | ... | |
| 87 | 97 |
for sensor in data['sensors'].values(): |
| 88 | 98 |
if sensor['type'] != 'ZLLLightLevel': |
| 89 | 99 |
continue |
| 90 |
label = cleanup(sensor['name'])
|
|
| 100 |
label = safename(sensor['name'])
|
|
| 91 | 101 |
if config: |
| 92 | 102 |
print('{}.label {}'.format(label, sensor_name(data, sensor)))
|
| 93 | 103 |
if not config or both: |
| ... | ... | |
| 96 | 106 |
|
| 97 | 107 |
|
| 98 | 108 |
def print_lights(data, config, both): |
| 99 |
"""Lights on/off.""" |
|
| 109 |
"""Light bulbs on/off."""
|
|
| 100 | 110 |
if not data['lights']: |
| 101 | 111 |
return |
| 102 | 112 |
|
| ... | ... | |
| 120 | 130 |
def print_data(config): |
| 121 | 131 |
"""Print config or values.""" |
| 122 | 132 |
# Get values |
| 123 |
data = requests.get('http://{}/api/{}/'.format(
|
|
| 124 |
os.getenv('host'), os.getenv('auth')), timeout=50).json()
|
|
| 133 |
url = 'http://{}/api/{}/'.format(os.getenv('host'), os.getenv('auth'))
|
|
| 134 |
try: |
|
| 135 |
data = json.loads(urllib.request.urlopen(url, timeout=50).read()) |
|
| 136 |
except (OSError, ValueError, TypeError): |
|
| 137 |
return |
|
| 125 | 138 |
both = os.getenv('MUNIN_CAP_DIRTYCONFIG') == '1'
|
| 126 | 139 |
|
| 127 | 140 |
# Print config/values |
| ... | ... | |
| 132 | 145 |
|
| 133 | 146 |
if __name__ == '__main__': |
| 134 | 147 |
if len(sys.argv) > 1 and sys.argv[1] == 'autoconf': |
| 135 |
print('no')
|
|
| 148 |
print('no (this is not autoconf plugin)')
|
|
| 136 | 149 |
elif len(sys.argv) > 1 and sys.argv[1] == 'config': |
| 137 | 150 |
print_data(True) |
| 138 | 151 |
else: |
Formats disponibles : Unified diff