Rev 3 | Rev 5 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3 | Rev 4 | ||
---|---|---|---|
Line 7... | Line 7... | ||
7 | import cgi |
7 | import cgi |
8 | import time |
8 | import time |
9 | import requests |
9 | import requests |
10 | import subprocess |
10 | import subprocess |
11 | import config |
11 | import config |
- | 12 | import threading |
|
12 | 13 | ||
13 | g_subscribed = [] |
14 | g_subscribed = [] |
14 | 15 | ||
15 | class S(BaseHTTPRequestHandler): |
16 | class S(BaseHTTPRequestHandler): |
16 | def _output(self, code, content): |
17 | def _output(self, code, content): |
Line 23... | Line 24... | ||
23 | try: |
24 | try: |
24 | action = parse_qs(self.path[2:]).get("action")[0] |
25 | action = parse_qs(self.path[2:]).get("action")[0] |
25 | except: |
26 | except: |
26 | action = None |
27 | action = None |
27 | 28 | ||
28 | output = '''<html> |
29 | output = '''<!DOCTYPE html> |
- | 30 | <html lang="en"> |
|
29 | 31 | ||
30 | <head> |
32 | <head> |
- | 33 | <meta charset="UTF-8"> |
|
31 | <title>Motion camera</title> |
34 | <title>Motion camera</title> |
32 | </head> |
35 | </head> |
33 | 36 | ||
34 | <body onload="onload()"> |
37 | <body onload="onload()"> |
35 | 38 | ||
Line 38... | Line 41... | ||
38 | function sleep (time) { |
41 | function sleep (time) { |
39 | return new Promise((resolve) => setTimeout(resolve, time)); |
42 | return new Promise((resolve) => setTimeout(resolve, time)); |
40 | } |
43 | } |
41 | 44 | ||
42 | function _toggle_alarm(st) { |
45 | function _toggle_alarm(st) { |
43 | document.getElementById("pleasewait").innerHTML = ' <i>Bitte warten</i>...'; |
46 | document.getElementById("pleasewait").innerHTML = ' <i>Please wait...</i>'; |
44 | var xhr = new XMLHttpRequest(); |
47 | var xhr = new XMLHttpRequest(); |
45 | xhr.onreadystatechange = function () { |
48 | xhr.onreadystatechange = function () { |
46 | var DONE = 4; // readyState 4 means the request is done. |
49 | var DONE = 4; // readyState 4 means the request is done. |
47 | var OK = 200; // status 200 is a successful return. |
50 | var OK = 200; // status 200 is a successful return. |
48 | if (xhr.readyState === DONE) { |
51 | if (xhr.readyState === DONE) { |
Line 56... | Line 59... | ||
56 | } |
59 | } |
57 | }; |
60 | }; |
58 | 61 | ||
59 | var data = new FormData(); |
62 | var data = new FormData(); |
60 | data.append('action', st ? 'motion_on'/*1.3.6.1.4.1.37476.2.4.1.100*/ : 'motion_off'/*1.3.6.1.4.1.37476.2.4.1.101*/); |
63 | data.append('action', st ? 'motion_on'/*1.3.6.1.4.1.37476.2.4.1.100*/ : 'motion_off'/*1.3.6.1.4.1.37476.2.4.1.101*/); |
61 | xhr.open('POST', '/', true); |
64 | xhr.open('POST', document.location, true); |
62 | xhr.send(data); |
65 | xhr.send(data); |
63 | } |
66 | } |
64 | 67 | ||
65 | function onload() { |
68 | function onload() { |
- | 69 | if (document.getElementById('campic') != null) { |
|
66 | document.getElementById('campic').src = 'http://' + window.location.hostname + ':'''+str(config.motion_stream_port)+'''/'; |
70 | document.getElementById('campic').src = 'http://' + window.location.hostname + ':'''+str(config.motion_stream_port)+'''/'; |
67 | } |
71 | } |
- | 72 | } |
|
68 | 73 | ||
69 | </script>''' |
74 | </script>''' |
70 | 75 | ||
71 | if ismotionrunning(): |
76 | if ismotionrunning(): |
72 | output = output + '<h2>Motion detection ON</h2>'; |
77 | output = output + '<h2>Motion detection ON</h2>' |
73 | output = output + '<p><a href="javascript:_toggle_alarm(0)">Disable motion detection</a><span id="pleasewait"></span></p>'; |
78 | output = output + '<p><a href="javascript:_toggle_alarm(0)">Disable motion detection</a><span id="pleasewait"></span></p>' |
- | 79 | output = output + '<p>Showing camera stream from port {0}. If you don\'t see a picture, please check your configuration or firewall.</p>'.format(config.motion_stream_port) |
|
74 | output = output + '<p><img id="campic" src="" alt="Camera picture"></p>'; |
80 | output = output + '<p><img id="campic" src="" alt=""></p>'; |
75 | else: |
81 | else: |
76 | output = output + '<h2>Motion detection OFF</h2>'; |
82 | output = output + '<h2>Motion detection OFF</h2>' |
77 | output = output + '<p><a href="javascript:_toggle_alarm(1)">Enable motion detection</a><span id="pleasewait"></span></p>'; |
83 | output = output + '<p><a href="javascript:_toggle_alarm(1)">Enable motion detection</a><span id="pleasewait"></span></p>' |
78 | 84 | ||
79 | output = output + '<h2>Subscribers</h2>' |
85 | output = output + '<h2>Subscribers</h2>' |
80 | 86 | ||
81 | found_subs = 0 |
87 | found_subs = 0 |
82 | for x in g_subscribed[:]: |
88 | for x in g_subscribed[:]: |
Line 95... | Line 101... | ||
95 | self._output(200, output) |
101 | self._output(200, output) |
96 | 102 | ||
97 | def do_HEAD(self): |
103 | def do_HEAD(self): |
98 | self._output(200, '') |
104 | self._output(200, '') |
99 | 105 | ||
- | 106 | def thr_client_notify(self, client_ip, client_port, server_targets): |
|
- | 107 | print "ALERT: Will alert client http://{0}:{1} and tell that targets {2} sent an alert".format(client_ip, client_port, server_targets) |
|
- | 108 | d = {"action": "client_alert", # 1.3.6.1.4.1.37476.2.4.1.3 |
|
- | 109 | "targets": server_targets, |
|
- | 110 | "motion_port": config.motion_stream_port, |
|
- | 111 | "simulation": "0"} |
|
- | 112 | requests.post("http://{0}:{1}".format(client_ip, client_port), data=d) |
|
- | 113 | ||
100 | def do_POST(self): |
114 | def do_POST(self): |
101 | # https://stackoverflow.com/questions/4233218/python-how-do-i-get-key-value-pairs-from-the-basehttprequesthandler-http-post-h |
115 | # https://stackoverflow.com/questions/4233218/python-how-do-i-get-key-value-pairs-from-the-basehttprequesthandler-http-post-h |
102 | # TODO: do we need the cgi package, or can we use functions available in this class (e.g. self_parse_qs?) |
116 | # Question: Do we need the cgi package, or can we use functions available in this class (e.g. self_parse_qs?) |
103 | ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) |
117 | ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) |
104 | if ctype == 'multipart/form-data': |
118 | if ctype == 'multipart/form-data': |
105 | postvars = cgi.parse_multipart(self.rfile, pdict) |
119 | postvars = cgi.parse_multipart(self.rfile, pdict) |
106 | elif ctype == 'application/x-www-form-urlencoded': |
120 | elif ctype == 'application/x-www-form-urlencoded': |
107 | length = int(self.headers.getheader('content-length')) |
121 | length = int(self.headers.getheader('content-length')) |
Line 143... | Line 157... | ||
143 | if pvget(postvars, "action")[0] == "server_alert": # 1.3.6.1.4.1.37476.2.4.1.2 |
157 | if pvget(postvars, "action")[0] == "server_alert": # 1.3.6.1.4.1.37476.2.4.1.2 |
144 | server_targets = pvget(postvars, "targets") |
158 | server_targets = pvget(postvars, "targets") |
145 | 159 | ||
146 | found_g = 0 |
160 | found_g = 0 |
147 | 161 | ||
148 | # TODO: this should be done in parallel threads, so that we can notify every client as fast as possible! |
- | |
149 | for x in g_subscribed: |
162 | for subscriber in g_subscribed: |
150 | client_ip = x[0] |
163 | client_ip = subscriber[0] |
151 | client_port = x[1] |
164 | client_port = subscriber[1] |
152 | client_expires = x[2] |
165 | client_expires = subscriber[2] |
153 | client_targets = x[3] |
166 | client_targets = subscriber[3] |
154 | found_c = 0 |
167 | found_c = 0 |
155 | for st in server_targets: |
168 | for st in server_targets: |
156 | for ct in client_targets: |
169 | for ct in client_targets: |
157 | if ct == st: |
170 | if ct == st: |
158 | found_c = found_c + 1 |
171 | found_c = found_c + 1 |
159 | found_g = found_g + 1 |
172 | found_g = found_g + 1 |
160 | if found_c > 0: |
173 | if found_c > 0: |
161 | print "ALERT: Will alert client http://{0}:{1} and tell that targets {2} sent an alert".format(client_ip, client_port, server_targets) |
174 | # Notify clients via threads, so that all clients are equally fast notified |
162 | d = {"action": "client_alert", # 1.3.6.1.4.1.37476.2.4.1.3 |
175 | thread = threading.Thread(target=self.thr_client_notify, args=(client_ip, client_port, server_targets, )) |
163 | "targets": server_targets, |
176 | thread.start() |
164 | "motion_port": config.motion_stream_port, |
- | |
165 | "simulation": "0"} |
- | |
166 | requests.post("http://{0}:{1}".format(client_ip, client_port), data=d) |
- | |
167 | 177 | ||
168 | if found_g == 0: |
178 | if found_g == 0: |
169 | print "ALERT {0}, but nobody is listening!".format(server_targets) |
179 | print "ALERT {0}, but nobody is listening!".format(server_targets) |
170 | 180 | ||
171 | - | ||
172 | if pvget(postvars, "action")[0] == "motion_on": # 1.3.6.1.4.1.37476.2.4.1.100 |
181 | if pvget(postvars, "action")[0] == "motion_on": # 1.3.6.1.4.1.37476.2.4.1.100 |
173 | print "Motion start" |
182 | print "Motion start" |
174 | os.system(os.path.dirname(os.path.abspath(__file__)) + "/motion/motion_start_safe") |
183 | os.system(os.path.dirname(os.path.abspath(__file__)) + "/motion/motion_start_safe") |
175 | 184 | ||
176 | if pvget(postvars, "action")[0] == "motion_off": # 1.3.6.1.4.1.37476.2.4.1.101 |
185 | if pvget(postvars, "action")[0] == "motion_off": # 1.3.6.1.4.1.37476.2.4.1.101 |
Line 184... | Line 193... | ||
184 | return [""] |
193 | return [""] |
185 | else: |
194 | else: |
186 | return ary.get(key) |
195 | return ary.get(key) |
187 | 196 | ||
188 | def run(server_class=HTTPServer, handler_class=S, port=8085): |
197 | def run(server_class=HTTPServer, handler_class=S, port=8085): |
- | 198 | print 'Starting server, listening to port {0}...'.format(port) |
|
189 | server_address = ('', port) |
199 | server_address = ('', port) |
190 | httpd = server_class(server_address, handler_class) |
200 | httpd = server_class(server_address, handler_class) |
191 | print 'Starting httpd...' |
- | |
192 | httpd.serve_forever() |
201 | httpd.serve_forever() |
193 | 202 | ||
194 | def ismotionrunning(): |
203 | def ismotionrunning(): |
195 | p = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE) |
204 | p = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE) |
196 | out, err = p.communicate() |
205 | out, err = p.communicate() |