Skip to content

Commit 3107425

Browse files
author
yfauser
committed
added setuptools info and changed main to work with setuptools entry points
1 parent 6c350e6 commit 3107425

File tree

17 files changed

+292
-64
lines changed

17 files changed

+292
-64
lines changed

.gitignore

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
openweathermap-api-example
2-
/.idea/
3-
*.pyc
4-
/notifier_modules/*.pyc
2+
/maxwindownotify/.idea/
3+
/maxwindownotify/*.pyc
4+
/maxwindownotify/notifier_modules/*.pyc
5+
.DS_Store
6+
.idea
7+
8+
59

610

711

dist/maxwindownotify-1.0.tar.gz

9.86 KB
Binary file not shown.

maxwindownotify.egg-info/PKG-INFO

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
Metadata-Version: 1.1
2+
Name: maxwindownotify
3+
Version: 1.0
4+
Summary: This little script (daemon) will poll for the status of all window sensors known to a MAX Cube system and check for open windows
5+
Home-page: http://github.com/yfauser/maxwindownotify
6+
Author: yfauser
7+
Author-email: yfauser@yahoo.de
8+
License: MIT
9+
Description: Max Open Window Notifier
10+
========================
11+
12+
This little script (daemon) will poll for the status of all window
13+
sensors known to a MAX Cube system (http://www.eq-3.de) and check for
14+
open windows.
15+
16+
It will then check the temperature at the location of your house using
17+
Open Weather Map (http://openweathermap.org), and if the temperature is
18+
bellow a specified threshold it will send a notification using a
19+
notifier plugin.
20+
21+
Today the only available notifier plugin is using the Pushover service
22+
(https://pushover.net) to send notifications e.g. to mobile phones.
23+
24+
It has been created to safe energy by reminding you to close your
25+
windows after ventilation.
26+
27+
Installation
28+
------------
29+
30+
Max Open Window Notifier can be installed using PIP
31+
32+
.. code:: bash
33+
34+
sudo pip install maxwindownotify
35+
36+
Usage
37+
~~~~~
38+
39+
You can use the CLI help function to get the details on how to start the
40+
daemon, and what options are available:
41+
42+
.. code:: bash
43+
44+
$ python maxwindownotify.py --help
45+
usage: maxwindownotify.py [-h] [-i INTERVAL] [-n NETWORK] [-c CITY]
46+
[-t THRESHOLD] -k OWMAPPID [-s] [-u USER] [-p TOKEN]
47+
[-v]
48+
49+
This deamon polls the MAX Cube for all window status. If a window is open
50+
longer than twice the poll interval a notification will be sent using the
51+
notifier plugin
52+
53+
optional arguments:
54+
-h, --help show this help message and exit
55+
-i INTERVAL, --interval INTERVAL
56+
polling interval in minutes (default 30 minutes)
57+
-n NETWORK, --network NETWORK
58+
Network Address to send search broadcast for MAX Cube
59+
(default 192.168.178.0/24)
60+
-c CITY, --city CITY the city name or code in OpenWeatherMap to retrieve
61+
the outside temperature from (default Munich, Germany)
62+
-t THRESHOLD, --threshold THRESHOLD
63+
the temperature threshold for suppressing
64+
notifications (default: 12C)
65+
-k OWMAPPID, --owmappid OWMAPPID
66+
the API Key (APPID) to authenticate with Open Weather
67+
Map
68+
-s, --simulation randomly simulate open windows
69+
-u USER, --user USER the username (or user key) used for the notifier
70+
module
71+
-p TOKEN, --token TOKEN
72+
the password (or app token) used for the notifier
73+
module
74+
-v, --verbose increase output verbosity
75+
76+
As an alternative to the commandline, params can be placed in a file, one per
77+
line, and specified on the commandline like 'maxwindownotify.py @params.conf'.
78+
79+
Example:
80+
81+
.. code:: bash
82+
83+
python maxwindownotify.py -k 82k4v1b99s41212e5bf5490432bb89f4 -u abcCKnM9uYhjng3kLV6czGFUsmZ76D -p ahxYZcjhXT6P5zDt265LGyuLVaDQNx -i 15 -c Berlin -t 8
84+
85+
Platform: UNKNOWN
86+
Classifier: Development Status :: 5 - Production/Stable
87+
Classifier: Intended Audience :: End Users/Desktop
88+
Classifier: Topic :: Utilities
89+
Classifier: License :: OSI Approved :: MIT License
90+
Classifier: Programming Language :: Python :: 2.7
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
README.rst
2+
setup.py
3+
maxwindownotify/__init__.py
4+
maxwindownotify/maxwindownotify.py
5+
maxwindownotify.egg-info/PKG-INFO
6+
maxwindownotify.egg-info/SOURCES.txt
7+
maxwindownotify.egg-info/dependency_links.txt
8+
maxwindownotify.egg-info/entry_points.txt
9+
maxwindownotify.egg-info/requires.txt
10+
maxwindownotify.egg-info/top_level.txt
11+
maxwindownotify/notifier_modules/__init__.py
12+
maxwindownotify/notifier_modules/__init__.pyc
13+
maxwindownotify/notifier_modules/pushover_notifier.py
14+
maxwindownotify/notifier_modules/pushover_notifier.pyc
15+
maxwindownotify/notifier_modules/stdout_notifier.py
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[console_scripts]
2+
maxwindownotify = maxwindownotify.maxwindownotify:main
3+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests>=2.7.0
2+
netaddr>=0.7.18
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
maxwindownotify
File renamed without changes.

maxwindownotify.py renamed to maxwindownotify/maxwindownotify.py

Lines changed: 59 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ def discover_cube(self):
121121
logging.log(logging.ERROR, 'Could not send UDP discover brodcast, socket error is: {}'.format(e))
122122
sys.exit()
123123

124+
cube_data = None
125+
cube_ip = None
126+
124127
while True:
125128
try:
126129
recv_data, recvaddr = udp_recv_socket.recvfrom(4096)
@@ -152,8 +155,8 @@ def _get_cube_data(self):
152155
tcp_socket.connect((self.cube_ip, self.cube_port))
153156
except (socket.timeout, socket.error) as e:
154157
logging.log(logging.ERROR, 'Could not open TCP connection to MAX Cube, socket error is: {}'.format(e))
155-
return None
156158
tcp_socket.close()
159+
return None
157160

158161
received_data = b''
159162
logging.log(logging.INFO, 'connecting to MAX Cube to retrieve data')
@@ -193,21 +196,16 @@ def _decode_m_line(m_line):
193196

194197
data['rooms'] = {}
195198
for i in range(data['room_count']):
196-
room = {}
197-
room['id'] = ord(decoded.read(1))
198-
room['name_len'] = ord(decoded.read(1))
199+
room = {'id': ord(decoded.read(1)), 'name_len': ord(decoded.read(1))}
199200
room['name'] = decoded.read(room['name_len'])
200201
room['rf_address'] = binascii.b2a_hex(decoded.read(3))
201202
data['rooms'][room['id']] = room
202203

203204
data['devices_count'] = ord(decoded.read(1))
204205
data['devices'] = []
205206
for i in range(data['devices_count']):
206-
device = {}
207-
device['type'] = ord(decoded.read(1))
208-
device['rf_address'] = binascii.b2a_hex(decoded.read(3))
209-
device['serial'] = decoded.read(10)
210-
device['name_len'] = ord(decoded.read(1))
207+
device = {'type': ord(decoded.read(1)), 'rf_address': binascii.b2a_hex(decoded.read(3)),
208+
'serial': decoded.read(10), 'name_len': ord(decoded.read(1))}
211209
device['name'] = decoded.read(device['name_len'])
212210
device['room_id'] = ord(decoded.read(1))
213211
data['devices'].append(device)
@@ -304,57 +302,7 @@ def get_current_temperature(self, city, units='metric'):
304302
return None
305303

306304

307-
def main(args, loglevel):
308-
last_window_status = None
309-
logging.basicConfig(format="%(asctime)-15s %(levelname)s: %(message)s", level=loglevel)
310-
notifier_log_http = False
311-
if loglevel == logging.DEBUG:
312-
notifier_log_http = True
313-
if args.user and args.token:
314-
notify = Notifier(user=args.user, token=args.token, debug=notifier_log_http)
315-
else:
316-
notify = Notifier()
317-
318-
temperature = OpenWeatherMap(args.owmappid)
319-
320-
logging.log(logging.INFO, 'searching for MAX Cube in the network')
321-
max_cube = MaxConnection(discover_ip_subnet=args.network)
322-
323-
while True:
324-
skip_run = False
325-
window_status = max_cube.window_switch_status(args.simulation)
326-
logging.log(logging.INFO, 'current window data: {}'.format(window_status))
327-
outside_temperature = temperature.get_current_temperature(args.city)
328-
logging.log(logging.INFO, 'current temperature in {}: {}'.format(args.city, outside_temperature))
329-
330-
if not window_status:
331-
skip_run = True
332-
logging.log(logging.INFO, 'did not receive any data from MAX Cube, skipping this cycle')
333-
elif not outside_temperature:
334-
skip_run = True
335-
logging.log(logging.INFO, 'did not receive any temperature data, skipping this cycle')
336-
elif not outside_temperature <= args.threshold:
337-
skip_run = True
338-
logging.log(logging.INFO, 'current outside temperature above threshold of {}, skipping this '
339-
'cycle'.format(args.threshold))
340-
341-
if not last_window_status and window_status:
342-
last_window_status = window_status
343-
344-
if not skip_run:
345-
for rf_addr in window_status:
346-
if window_status[rf_addr]['status'] == 'open':
347-
if window_status[rf_addr]['status'] == last_window_status[rf_addr]['status']:
348-
logging.log(logging.INFO, 'sending notify because of open window')
349-
notify.send_msg('{} was open for more than {} minutes, and the temperature '
350-
'in {} is {}'.format(window_status[rf_addr]['name'],
351-
args.interval, args.city, outside_temperature))
352-
last_window_status = window_status
353-
logging.log(logging.INFO, 'sleeping for {} minutes'.format(args.interval))
354-
time.sleep(int(args.interval)*60)
355-
356-
357-
if __name__ == '__main__':
305+
def main():
358306
parser = argparse.ArgumentParser(description="This deamon polls the MAX Cube for all window status. "
359307
"If a window is open longer than twice the poll interval a "
360308
"notification will be sent using the notifier plugin",
@@ -405,4 +353,54 @@ def main(args, loglevel):
405353
else:
406354
loglevel = logging.WARNING
407355

408-
main(args, loglevel)
356+
last_window_status = None
357+
logging.basicConfig(format="%(asctime)-15s %(levelname)s: %(message)s", level=loglevel)
358+
notifier_log_http = False
359+
if loglevel == logging.DEBUG:
360+
notifier_log_http = True
361+
if args.user and args.token:
362+
notify = Notifier(user=args.user, token=args.token, debug=notifier_log_http)
363+
else:
364+
notify = Notifier()
365+
366+
temperature = OpenWeatherMap(args.owmappid)
367+
368+
logging.log(logging.INFO, 'searching for MAX Cube in the network')
369+
max_cube = MaxConnection(discover_ip_subnet=args.network)
370+
371+
while True:
372+
skip_run = False
373+
window_status = max_cube.window_switch_status(args.simulation)
374+
logging.log(logging.INFO, 'current window data: {}'.format(window_status))
375+
outside_temperature = temperature.get_current_temperature(args.city)
376+
logging.log(logging.INFO, 'current temperature in {}: {}'.format(args.city, outside_temperature))
377+
378+
if not window_status:
379+
skip_run = True
380+
logging.log(logging.INFO, 'did not receive any data from MAX Cube, skipping this cycle')
381+
elif not outside_temperature:
382+
skip_run = True
383+
logging.log(logging.INFO, 'did not receive any temperature data, skipping this cycle')
384+
elif not outside_temperature <= args.threshold:
385+
skip_run = True
386+
logging.log(logging.INFO, 'current outside temperature above threshold of {}, skipping this '
387+
'cycle'.format(args.threshold))
388+
389+
if not last_window_status and window_status:
390+
last_window_status = window_status
391+
392+
if not skip_run:
393+
for rf_addr in window_status:
394+
if window_status[rf_addr]['status'] == 'open':
395+
if window_status[rf_addr]['status'] == last_window_status[rf_addr]['status']:
396+
logging.log(logging.INFO, 'sending notify because of open window')
397+
notify.send_msg('{} was open for more than {} minutes, and the temperature '
398+
'in {} is {}'.format(window_status[rf_addr]['name'],
399+
args.interval, args.city, outside_temperature))
400+
last_window_status = window_status
401+
logging.log(logging.INFO, 'sleeping for {} minutes'.format(args.interval))
402+
time.sleep(int(args.interval)*60)
403+
404+
405+
if __name__ == '__main__':
406+
main()

0 commit comments

Comments
 (0)