aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mcrute@gmail.com>2013-08-29 09:19:44 -0400
committerMike Crute <mcrute@gmail.com>2013-08-29 09:19:44 -0400
commit62bcc93047f677f322422fb1c9a0fab3f1923008 (patch)
tree0564b91532e43ba0e02e0ab4a304ebac0ec3952f
parente43d2aa4813ad65d2034cb356872008bee0302cc (diff)
downloadubntmfi-62bcc93047f677f322422fb1c9a0fab3f1923008.tar.bz2
ubntmfi-62bcc93047f677f322422fb1c9a0fab3f1923008.tar.xz
ubntmfi-62bcc93047f677f322422fb1c9a0fab3f1923008.zip
Changing to web based manager
-rw-r--r--.gitignore1
-rw-r--r--mfiapi.py58
-rw-r--r--server.py46
-rw-r--r--templates/index.html18
4 files changed, 84 insertions, 39 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
*.pyc
diff --git a/mfiapi.py b/mfiapi.py
new file mode 100644
index 0000000..31f0330
--- /dev/null
+++ b/mfiapi.py
@@ -0,0 +1,58 @@
1import json
2import urllib2
3import urllib
4from cookielib import CookieJar
5
6def bool_to_bin(value):
7 return 1 if value == True else 0
8
9
10def bin_to_bool(value):
11 return True if int(value) == 1 else False
12
13
14class MFiAPI(object):
15
16 def __init__(self, host):
17 self.host = host
18 self.opener = urllib2.build_opener(
19 urllib2.HTTPCookieProcessor(CookieJar()))
20
21 def _make_url(self, suffix):
22 return 'https://{}/{}'.format(self.host, suffix)
23
24 def login(self, username, password):
25 form_data = urllib.urlencode({
26 'username' : username,
27 'password': password,
28 'login': 'login'
29 })
30
31 self.opener.open(self._make_url('login'), form_data)
32
33 def get_sensor_data(self):
34 resp = self.opener.open(self._make_url('api/v1.0/list/sensors'))
35 return json.load(resp)['data']
36
37 def port_status(self):
38 data = self.get_sensor_data()
39 return dict((i['label'], bin_to_bool(i['output_val'])) for i in data)
40
41 def set_port(self, mac, port, value):
42 data = urllib.urlencode({ "json": json.dumps({
43 "mac": mac,
44 "val": bool_to_bin(value),
45 "port": int(port),
46 "cmd": "mfi-output"
47 })
48 })
49
50 self.opener.open(self._make_url("api/v1.0/cmd/devmgr"), data)
51
52 def toggle_port(self, name):
53 mac, port, status = None, None, None
54
55 for data in self.get_sensor_data():
56 if data['label'] == name:
57 set_to = not bin_to_bool(data['output_val'])
58 self.set_port(data['mac'], data['port'], set_to)
diff --git a/server.py b/server.py
index 766cc5f..4159736 100644
--- a/server.py
+++ b/server.py
@@ -6,49 +6,41 @@ import tornado.options
6import tornado.process 6import tornado.process
7import tornado.template 7import tornado.template
8import tornado.httpserver 8import tornado.httpserver
9from mfiapi import MFiAPI
9from tornado.options import define, options 10from tornado.options import define, options
10 11
11define("port", default=8888, help="run on the given port", type=int) 12define("port", default=8888, help="run on the given port", type=int)
12 13
13 14
14STATUSES = {
15 'relay1': True, # Fan
16 'relay2': False, # Light
17 'relay3': False,
18}
19
20
21# for relay in STATUSES.keys():
22# caller = subprocess.Popen(["ssh","admin@10.0.1.15",
23# "cat /proc/power/{}".format(relay)], stdout=subprocess.PIPE)
24# output = caller.communicate()[0]
25# STATUSES[relay] = output.startswith("1")
26
27
28class PowerStatusHandler(tornado.web.RequestHandler): 15class PowerStatusHandler(tornado.web.RequestHandler):
29 16
30 def get(self): 17 def __init__(self, *args, **kwargs):
31 self.finish(STATUSES) 18 self.api = MFiAPI('172.16.0.38:6443')
19 super(PowerStatusHandler, self).__init__(*args, **kwargs)
32 20
33 @tornado.web.asynchronous 21 def get(self):
34 def _trigger_relay(self, relay, value): 22 self.api.login('admin', 'password')
35 STATUSES[relay] = value 23 self.finish(self.api.port_status())
36 value = 1 if value is True else 0
37 tornado.process.Subprocess(["ssh","admin@10.0.1.15",
38 "echo {} > /proc/power/{}".format(value, relay)],
39 stdout=tornado.process.Subprocess.STREAM)
40 24
41 def post(self): 25 def post(self):
42 for key, value in self.request.arguments.items(): 26 self.api.login('admin', 'password')
43 self._trigger_relay(key, value[0] == "on")
44 27
45 self.finish(STATUSES) 28 for key, value in self.request.arguments.items():
29 self.api.toggle_port(key)
46 30
47 31
48class IndexHandler(tornado.web.RequestHandler): 32class IndexHandler(tornado.web.RequestHandler):
49 33
34 def __init__(self, *args, **kwargs):
35 self.api = MFiAPI('172.16.0.38:6443')
36 super(IndexHandler, self).__init__(*args, **kwargs)
37
50 def get(self): 38 def get(self):
51 self.render("index.html") 39 self.api.login('admin', 'password')
40
41 ports = [(port, port.replace(" ", "_").replace("'", "-")) for port in self.api.port_status().keys()]
42
43 self.render("index.html", ports=ports)
52 44
53 45
54class Application(tornado.web.Application): 46class Application(tornado.web.Application):
diff --git a/templates/index.html b/templates/index.html
index dba7d79..6903a10 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -13,12 +13,13 @@
13 $.ajax("/power-status/").done(function(data) { 13 $.ajax("/power-status/").done(function(data) {
14 for (key in data) { 14 for (key in data) {
15 var value = data[key] ? "on" : "off"; 15 var value = data[key] ? "on" : "off";
16 var key = key.replace("'", "-").replace(" ", "_");
16 $("#"+key).val(value).slider("refresh"); 17 $("#"+key).val(value).slider("refresh");
17 } 18 }
18 }); 19 });
19 $("select[data-role=slider]").on("change", function() { 20 $("select[data-role=slider]").on("change", function() {
20 var data = {}; 21 var data = {};
21 data[this.name] = $(this).val(); 22 data[$(this).attr("data-name")] = $(this).val();
22 $.ajax({ url: "/power-status/", data: data, type: "POST" }); 23 $.ajax({ url: "/power-status/", data: data, type: "POST" });
23 }); 24 });
24 }); 25 });
@@ -32,24 +33,17 @@
32 33
33 <div data-role="content"> 34 <div data-role="content">
34 <form> 35 <form>
36 {% for name, id in ports %}
35 <div class="ui-grid-a"> 37 <div class="ui-grid-a">
36 <div class="ui-block-a"><div class="ui-bar" style="height:60px"> 38 <div class="ui-block-a"><div class="ui-bar" style="height:60px">
37 <label for="relay2">Light</label> 39 <label for="{{ id }}">{{ name }}</label>
38 <select name="relay2" id="relay2" data-role="slider"> 40 <select name="{{ id }}" id="{{ id }}" data-name="{{ name }}" data-role="slider">
39 <option value="off">Off</option>
40 <option value="on">On</option>
41 </select>
42 </div></div>
43 </div><!-- /grid-a -->
44 <div class="ui-grid-a">
45 <div class="ui-block-a"><div class="ui-bar" style="height:60px">
46 <label for="relay1">Fan</label>
47 <select name="relay1" id="relay1" data-role="slider">
48 <option value="off">Off</option> 41 <option value="off">Off</option>
49 <option value="on">On</option> 42 <option value="on">On</option>
50 </select> 43 </select>
51 </div></div> 44 </div></div>
52 </div><!-- /grid-a --> 45 </div><!-- /grid-a -->
46 {% end %}
53 </form> 47 </form>
54 </div><!-- /content --> 48 </div><!-- /content -->
55 </div> 49 </div>