index.html 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>MiLight Hub</title>
  6. <meta name="description" content="The HTML5 Herald">
  7. <meta name="author" content="SitePoint">
  8. <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
  9. <link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet"/>
  10. <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.0/css/bootstrap-slider.min.css" rel="stylesheet"/>
  11. <!--[if lt IE 9]>
  12. <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
  13. <![endif]-->
  14. <style>
  15. .header-row { border-bottom: 1px solid #ccc; }
  16. label { display: block; }
  17. .radio-option { padding: 0 5px; cursor: pointer; }
  18. .command-buttons { list-style: none; margin: 0; padding: 0; }
  19. .command-buttons li { display: inline-block; margin-right: 1em; }
  20. .form-entry { margin: 0 0 20px 0; }
  21. .form-entry .form-control { width: 20em; }
  22. .btn-secondary {
  23. background-color: #fff;
  24. border: 1px solid #ccc;
  25. }
  26. .hue-picker {
  27. height: 2em;
  28. width: 100%;
  29. display: block;
  30. }
  31. .hue-picker-inner {
  32. height: 2em;
  33. width: calc(100% - 3em);
  34. display: inline-block;
  35. cursor: pointer;
  36. background: linear-gradient(to right,
  37. rgb(255, 0, 0) 0%,
  38. rgb(255, 255, 0) 16.6667%,
  39. rgb(0, 255, 0) 33.3333%,
  40. rgb(0, 255, 255) 50%,
  41. rgb(0, 0, 255) 66.6667%,
  42. rgb(255, 0, 255) 83.3333%,
  43. rgb(255, 0, 0) 100%
  44. );
  45. }
  46. .hue-value-display {
  47. border: 1px solid #000;
  48. margin-left: 0.5em;
  49. width: 2em;
  50. height: 2em;
  51. display: inline-block;
  52. }
  53. </style>
  54. </head>
  55. <body>
  56. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  57. <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  58. <script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
  59. <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
  60. <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.0/bootstrap-slider.min.js"></script>
  61. <script lang="text/javascript">
  62. var FORM_SETTINGS = ["admin_username", "admin_password", "ce_pin", "csn_pin"];
  63. var activeUrl = function() {
  64. var deviceId = $('input[name="deviceId"]').val()
  65. , groupId = $('#groupId input:checked').data('value');
  66. if (deviceId == "") {
  67. alert("Please enter a device ID.");
  68. throw "abc";
  69. }
  70. return "/gateways/" + deviceId + "/" + groupId;
  71. }
  72. var updateGroup = _.throttle(
  73. function(params) {
  74. $.ajax(
  75. activeUrl(),
  76. {
  77. method: 'PUT',
  78. data: JSON.stringify(params),
  79. contentType: 'application/json'
  80. }
  81. );
  82. },
  83. 1000
  84. );
  85. var sniffRequest;
  86. var sniffing = false;
  87. var getTraffic = function() {
  88. sniffRequest = $.get('/gateway_traffic', function(data) {
  89. $('#sniffed-traffic').html(data + $('#sniffed-traffic').html());
  90. getTraffic();
  91. });
  92. };
  93. var loadSettings = function() {
  94. $.getJSON('/settings', function(val) {
  95. Object.keys(val).forEach(function(k) {
  96. $('#settings input[name="' + k + '"]').val(val[k]);
  97. });
  98. });
  99. };
  100. $(function() {
  101. $('.radio-option').click(function() {
  102. $(this).prev().prop('checked', true);
  103. });
  104. var hueDragging = false;
  105. var colorUpdated = function(e) {
  106. var x = e.pageX - $(this).offset().left
  107. , pct = x/(1.0*$(this).width())
  108. , hue = Math.round(360*pct)
  109. ;
  110. $('.hue-value-display').css({
  111. backgroundColor: "hsl(" + hue + ",100%,50%)"
  112. });
  113. updateGroup({hue: hue});
  114. };
  115. $('.hue-picker-inner')
  116. .mousedown(function(e) {
  117. hueDragging = true;
  118. colorUpdated.call(this, e);
  119. })
  120. .mouseup(function(e) {
  121. hueDragging = false;
  122. })
  123. .mouseout(function(e) {
  124. hueDragging = false;
  125. })
  126. .mousemove(function(e) {
  127. if (hueDragging) {
  128. colorUpdated.call(this, e);
  129. }
  130. });
  131. $('.slider').slider();
  132. $('.raw-update').change(function() {
  133. var data = {}
  134. , val = $(this).attr('type') == 'checkbox' ? $(this).is(':checked') : $(this).val()
  135. ;
  136. data[$(this).attr('name')] = val;
  137. updateGroup(data);
  138. });
  139. $('.command-btn').click(function() {
  140. updateGroup({command: $(this).data('command')});
  141. });
  142. $('#sniff').click(function() {
  143. if (sniffing) {
  144. sniffRequest.abort();
  145. sniffing = false;
  146. $(this).html('Start Sniffing');
  147. } else {
  148. sniffing = true;
  149. getTraffic();
  150. $(this).html('Stop Sniffing');
  151. }
  152. });
  153. var settings = "";
  154. FORM_SETTINGS.forEach(function(k) {
  155. var elmt = '<div class="form-entry">';
  156. elmt += '<label for="' + k + '">' + k + '</label>';
  157. elmt += '<input type="text" class="form-control" name="' + k + '"/>';
  158. elmt += '</div>';
  159. settings += elmt;
  160. });
  161. $('#settings').prepend(settings);
  162. $('#settings').submit(function(e) {
  163. var obj = {};
  164. FORM_SETTINGS.forEach(function(k) {
  165. obj[k] = $('#settings input[name="' + k + '"]').val();
  166. });
  167. $.ajax(
  168. "/settings",
  169. {
  170. method: 'post',
  171. contentType: 'application/json',
  172. data: JSON.stringify(obj)
  173. }
  174. );
  175. e.preventDefault();
  176. return false;
  177. });
  178. loadSettings();
  179. });
  180. </script>
  181. <div class="container">
  182. <div class="row header-row">
  183. <div class="col-sm-12">
  184. <h1>
  185. Control Lights
  186. </h1>
  187. </div>
  188. </div>
  189. <div>&nbsp;</div>
  190. <div class="row">
  191. <div class="col-sm-4">
  192. <label for="deviceId">Device Id</label>
  193. <input type="text" class="form-control" name="deviceId" />
  194. </div>
  195. <div class="col-sm-8">
  196. <label for="groupId">Group</label>
  197. <div class="btn-group" id="groupId" data-toggle="buttons">
  198. <label class="btn btn-secondary active">
  199. <input type="radio" name="options" autocomplete="off" data-value="1" checked> 1
  200. </label>
  201. <label class="btn btn-secondary">
  202. <input type="radio" name="options" autocomplete="off" data-value="2"> 2
  203. </label>
  204. <label class="btn btn-secondary">
  205. <input type="radio" name="options" autocomplete="off" data-value="3"> 3
  206. </label>
  207. <label class="btn btn-secondary">
  208. <input type="radio" name="options" autocomplete="off" data-value="4"> 4
  209. </label>
  210. </div>
  211. </div>
  212. </div>
  213. <div class="row">
  214. <div class="col-sm-12">
  215. <h5>Hue</h5>
  216. </div>
  217. </div>
  218. <div class="row">
  219. <div class="col-sm-6">
  220. <span class="hue-picker">
  221. <span class="hue-picker-inner"></span>
  222. <span class="hue-value-display"></span>
  223. </span>
  224. </div>
  225. </div>
  226. <div class="row">
  227. <div class="col-sm-6">
  228. <h5>Brightness</h5>
  229. </div>
  230. </div>
  231. <div class="row">
  232. <div class="col-sm-12">
  233. <input class="slider raw-update" name="level"
  234. data-slider-min="0"
  235. data-slider-max="100"
  236. data-slider-value="100"
  237. />
  238. </div>
  239. </div>
  240. <div class="row">
  241. <div class="col-sm-12">
  242. <h5>Commands</h5>
  243. </div>
  244. </div>
  245. <div class="row">
  246. <div class="col-sm-12">
  247. <ul class="command-buttons">
  248. <li>
  249. <input type="checkbox" name="status" class="raw-update" data-toggle="toggle" checked/>
  250. </li>
  251. <li>
  252. <button type="button" class="btn btn-secondary command-btn" data-command="set_white">White</button>
  253. </li>
  254. <li>
  255. <button type="button" class="btn btn-success command-btn" data-command="pair">
  256. <i class="glyphicon glyphicon-plus"></i>
  257. Pair
  258. </button>
  259. </li>
  260. <li>
  261. <button type="button" class="btn btn-danger command-btn" data-command="unpair">
  262. <i class="glyphicon glyphicon-remove"></i>
  263. Unpair
  264. </button>
  265. </li>
  266. </ul>
  267. </div>
  268. </div>
  269. <div class="row header-row">
  270. <div class="col-sm-12">
  271. <h1>Settings</h1>
  272. </div>
  273. </div>
  274. <div>&nbsp;</div>
  275. <div class="row">
  276. <div class="col-sm-12">
  277. <form action="#" id="settings">
  278. <input type="submit" class="btn btn-success" value="Submit" />
  279. </form>
  280. </div>
  281. </div>
  282. <div class="row header-row">
  283. <div class="col-sm-12">
  284. <h1>Sniff Traffic</h1>
  285. </div>
  286. </div>
  287. <div>&nbsp;</div>
  288. <div class="row">
  289. <div class="col-sm-12">
  290. <button type="button" id="sniff" class="btn btn-primary">Start Sniffing</button>
  291. <pre id="sniffed-traffic"></pre>
  292. </div>
  293. </div>
  294. </div>
  295. </body>
  296. </html>