Login | ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/alarming/trunk/Server/daemon.py
Revision: 3
Committed: Mon May 6 21:25:33 2019 UTC (16 months, 3 weeks ago) by daniel-marschall
Content type: text/x-python
File size: 6383 byte(s)
Log Message:
Initial release to SVN

File Contents

# Content
1 #!/usr/bin/env python
2
3 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
4 import SocketServer
5 from urlparse import parse_qs
6 import os
7 import cgi
8 import time
9 import requests
10 import subprocess
11 import config
12
13 g_subscribed = []
14
15 class S(BaseHTTPRequestHandler):
16 def _output(self, code, content):
17 self.send_response(code)
18 self.send_header('Content-type', 'text/html')
19 self.end_headers()
20 self.wfile.write(content)
21
22 def do_GET(self):
23 try:
24 action = parse_qs(self.path[2:]).get("action")[0]
25 except:
26 action = None
27
28 output = '''<html>
29
30 <head>
31 <title>Motion camera</title>
32 </head>
33
34 <body onload="onload()">
35
36 <script>
37
38 function sleep (time) {
39 return new Promise((resolve) => setTimeout(resolve, time));
40 }
41
42 function _toggle_alarm(st) {
43 document.getElementById("pleasewait").innerHTML = ' <i>Bitte warten</i>...';
44 var xhr = new XMLHttpRequest();
45 xhr.onreadystatechange = function () {
46 var DONE = 4; // readyState 4 means the request is done.
47 var OK = 200; // status 200 is a successful return.
48 if (xhr.readyState === DONE) {
49 if (xhr.status === OK) {
50 sleep(5000).then(() => {
51 document.location.reload();
52 });
53 } else {
54 alert('Error: ' + xhr.status); // An error occurred during the request.
55 }
56 }
57 };
58
59 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*/);
61 xhr.open('POST', '/', true);
62 xhr.send(data);
63 }
64
65 function onload() {
66 document.getElementById('campic').src = 'http://' + window.location.hostname + ':'''+str(config.motion_stream_port)+'''/';
67 }
68
69 </script>'''
70
71 if ismotionrunning():
72 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>';
74 output = output + '<p><img id="campic" src="" alt="Camera picture"></p>';
75 else:
76 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>';
78
79 output = output + '<h2>Subscribers</h2>'
80
81 found_subs = 0
82 for x in g_subscribed[:]:
83 if int(time.time()) > x[2]:
84 g_subscribed.remove(x)
85 else:
86 found_subs = found_subs + 1
87 output = output + "<p>{0}:{1}</p>".format(x[0], x[1])
88
89 if found_subs == 0:
90 output = output + '<p>None</p>'
91
92 output = output + '</body>'
93 output = output + '</html>'
94
95 self._output(200, output)
96
97 def do_HEAD(self):
98 self._output(200, '')
99
100 def do_POST(self):
101 # 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?)
103 ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
104 if ctype == 'multipart/form-data':
105 postvars = cgi.parse_multipart(self.rfile, pdict)
106 elif ctype == 'application/x-www-form-urlencoded':
107 length = int(self.headers.getheader('content-length'))
108 postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
109 else:
110 postvars = {}
111
112 # ---
113
114 global g_subscribed
115
116 if pvget(postvars, "action")[0] == "client_subscribe": # 1.3.6.1.4.1.37476.2.4.1.1
117 client_ip = self.client_address[0]
118 client_port = pvget(postvars, "port")[0]
119 client_ttl = pvget(postvars, "ttl")[0]
120 client_targets = pvget(postvars, "targets")
121
122 client_expires = int(time.time()) + int(client_ttl)
123
124 print "Client subscribed: {0}:{1}, searching for targets {2}".format(client_ip, client_port, client_targets)
125
126 # Remove all expired entries, and previous entries of that client
127 for x in g_subscribed[:]:
128 if int(time.time()) > x[2]:
129 g_subscribed.remove(x)
130 elif (x[0] == client_ip) and (x[1] == client_port) and (x[3] == client_targets):
131 g_subscribed.remove(x)
132
133 # Now add our new client
134 g_subscribed.append([client_ip, client_port, client_expires, client_targets])
135
136 # Send parameters of the device(s)
137 d = {"action": "client_alert", # 1.3.6.1.4.1.37476.2.4.1.3
138 "targets": ['1.3.6.1.4.1.37476.2.4.2.0', '1.3.6.1.4.1.37476.2.4.2.1002'],
139 "motion_port": config.motion_stream_port,
140 "simulation": "1"}
141 requests.post("http://{0}:{1}".format(client_ip, client_port), data=d)
142
143 if pvget(postvars, "action")[0] == "server_alert": # 1.3.6.1.4.1.37476.2.4.1.2
144 server_targets = pvget(postvars, "targets")
145
146 found_g = 0
147
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:
150 client_ip = x[0]
151 client_port = x[1]
152 client_expires = x[2]
153 client_targets = x[3]
154 found_c = 0
155 for st in server_targets:
156 for ct in client_targets:
157 if ct == st:
158 found_c = found_c + 1
159 found_g = found_g + 1
160 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)
162 d = {"action": "client_alert", # 1.3.6.1.4.1.37476.2.4.1.3
163 "targets": server_targets,
164 "motion_port": config.motion_stream_port,
165 "simulation": "0"}
166 requests.post("http://{0}:{1}".format(client_ip, client_port), data=d)
167
168 if found_g == 0:
169 print "ALERT {0}, but nobody is listening!".format(server_targets)
170
171
172 if pvget(postvars, "action")[0] == "motion_on": # 1.3.6.1.4.1.37476.2.4.1.100
173 print "Motion start"
174 os.system(os.path.dirname(os.path.abspath(__file__)) + "/motion/motion_start_safe")
175
176 if pvget(postvars, "action")[0] == "motion_off": # 1.3.6.1.4.1.37476.2.4.1.101
177 print "Motion stop"
178 os.system(os.path.dirname(os.path.abspath(__file__)) + "/motion/motion_stop_safe")
179
180 self._output(200, '')
181
182 def pvget(ary, key):
183 if ary.get(key) == None:
184 return [""]
185 else:
186 return ary.get(key)
187
188 def run(server_class=HTTPServer, handler_class=S, port=8085):
189 server_address = ('', port)
190 httpd = server_class(server_address, handler_class)
191 print 'Starting httpd...'
192 httpd.serve_forever()
193
194 def ismotionrunning():
195 p = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE)
196 out, err = p.communicate()
197 try:
198 return ('/usr/bin/motion' in str(out))
199 except:
200 res = os.system("pidof -x /usr/bin/motion > /dev/null")
201 return (res >> 8) == 0
202
203 if __name__ == "__main__":
204 from sys import argv
205
206 if len(argv) == 2:
207 run(port=int(argv[1]))
208 else:
209 run()
210

Properties

Name Value
svn:executable *