ESP8266 SHT21 sensor
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

client-script.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. // This is the client-side Javascript that receives the IPs of all available
  2. // local ESP-Weather modules, reads their values using the Websocket interface
  3. // and renders the graphs to visualize them.
  4. //
  5. // ----------------------------------------------------------------------------
  6. // "THE BEER-WARE LICENSE" (Revision 42):
  7. // <xythobuz@xythobuz.de> & <ghost-ghost@web.de> wrote this file. As long as
  8. // you retain this notice you can do whatever you want with this stuff. If we
  9. // meet some day, and you think this stuff is worth it, you can buy us a beer
  10. // in return. Thomas Buck & Christian Högerle
  11. // ----------------------------------------------------------------------------
  12. // Text Strings. Change these to translate.
  13. textAvailableSensors = "Available Sensors";
  14. textButtonNext = "Continue";
  15. homeTabName = "Home";
  16. sensorTabName = "Sensor";
  17. errorMessage = "Couldn't read sensor with IP: ";
  18. errorTitle = "Error: ";
  19. temperatureLabel = 'Temperature [C]';
  20. humidityLabel = 'Humidity [%RH]';
  21. temperatureHeading = "Temperature";
  22. humidityHeading = "Humidity";
  23. // Colors
  24. singleChartTempColor = "#337ab7";
  25. singleChartHumidColor = "#337ab7";
  26. preDefinedColors = Array(
  27. "#337ab7", "#ff0000", "#00ff00"
  28. );
  29. // Get current client-time for the graph X-axis labels
  30. var actTime = new Date();
  31. actTime = actTime.getHours() + ":" + (actTime.getMinutes() < 10 ? '0':'') + actTime.getMinutes();
  32. var arrSensor = Array(); // Data received from Websockets
  33. var currentState = "initial"; // "initial", "main", "1", "2", ...
  34. // Draw initial view when the page has been loaded
  35. $(document).ready(resizeAndRedraw);
  36. // Match graph canvases to their parent containers on resize
  37. $(window).on('resize', resizeAndRedraw, false);
  38. // Redraw current graph view, used for resizing
  39. function redraw(animate) {
  40. if (currentState === "initial") {
  41. initialView();
  42. } else if (currentState === "main") {
  43. generateView(arrSensor, animate);
  44. } else {
  45. var n = Math.floor(Number(currentState));
  46. if ((String(n) === currentState) && (n >= 0)) {
  47. generateGraph(false, arrSensor[(currentState - 1)], animate);
  48. } else {
  49. console.log("Invalid state: " + currentState);
  50. }
  51. }
  52. }
  53. function resize() {
  54. $("canvas").each(function(i, el) {
  55. $(el).attr({
  56. "width":$(el).parent().width(),
  57. "height":$(el).parent().outerHeight()
  58. });
  59. });
  60. }
  61. function resizeAndRedraw(animate) {
  62. resize();
  63. redraw(animate);
  64. }
  65. function initialView() {
  66. // Show first page and hide the graphs
  67. $('#startDiv').show();
  68. $('#dataDiv').hide();
  69. // Reset the button text
  70. $('#btnSubmit').empty();
  71. $('#btnSubmit').html(textButtonNext);
  72. // Reset heading with number of clients
  73. $('#listSensorsHeading').empty();
  74. $('#listSensorsHeading').html(textAvailableSensors + " (0/" + clients.length + ")");
  75. // Iterate all given client IPs and get their data using Websocket
  76. var count = [0];
  77. jQuery.each(clients, function(index, client) {
  78. webSocket(client, "2391", count, clients.length);
  79. });
  80. // Button to continue to graph view
  81. $("#btnSubmit").click(function(event) {
  82. currentState = "main";
  83. resizeAndRedraw(true);
  84. });
  85. }
  86. function webSocket(wsUri, wsPort, count, clientsCount) {
  87. websocket = new WebSocket("ws://" + wsUri + ":" + wsPort + "/");
  88. websocket.onopen = function(evt) {};
  89. websocket.onclose = function(evt) {};
  90. websocket.onmessage = function(evt) {
  91. var jsonData = jQuery.parseJSON(evt.data);
  92. count[0]++;
  93. var sensor = {id: count[0], ip: wsUri, currentTemp: jsonData['T'], currentHum: jsonData['H']};
  94. var arrEEPROM = Array();
  95. jQuery.each(jsonData['EEPROM'], function(index, data) {
  96. arrEEPROM.push(data);
  97. });
  98. sensor.arrEEPROM = arrEEPROM;
  99. arrSensor.push(sensor);
  100. $('#listSensorsHeading').html(textAvailableSensors + " (" + sensor.id + "/" + clientsCount + ")");
  101. $('#listSensors').append('<li class="list-group-item">' +
  102. ' Sensor ' + sensor.id +
  103. ' | IP: ' + sensor.ip +
  104. ' | Temperature: ' + sensor.currentTemp +
  105. ' | Humidity: ' + sensor.currentHum +
  106. '</li>');
  107. // Enable continue buttons when all modules have been reached
  108. if(count[0] == clientsCount) {
  109. $('#btnSubmit').prop("disabled", false);
  110. }
  111. };
  112. websocket.onerror = function(evt) {
  113. if($('#websocketError').length ) {
  114. $('.alert-danger').append(errorMessage + wsUri + '<br>');
  115. } else {
  116. $('#alertDiv').append('<div class="alert alert-danger" id="websocketError">' +
  117. '<strong>' + errorTitle
  118. + '</strong><br>' + errorMessage
  119. + wsUri + '<br></div>');
  120. }
  121. console.log("WebSocket Error: " + evt.data);
  122. };
  123. }
  124. function generateView(arrSensor, animation) {
  125. // Hide first page, show graph page
  126. $('#startDiv').hide();
  127. $('#dataDiv').show();
  128. // Add home tab
  129. $('.nav-pills').empty();
  130. $('.nav-pills').append('<li class="active"><a id="homebut" class="navtab" data-toggle="tab" href="#home">' + homeTabName + '</a></li>');
  131. // Add tabs for all sensors
  132. jQuery.each(arrSensor, function(index, sensor) {
  133. $('.nav-pills').append('<li><a id="sensbut" class="navtab" data-toggle="tab" href="#' + sensor.id + '">' + sensorTabName + ' ' + sensor.id + '</a></li>');
  134. });
  135. // flag for combined plot -> true
  136. generateGraph(true, arrSensor, animation);
  137. // Handler for "Home" button, drawing combined graph
  138. $("#homebut").click(function(event) {
  139. // flag for combined plot -> true
  140. generateGraph(true, arrSensor, true);
  141. currentState = "main";
  142. });
  143. // Handler for single sensor buttons
  144. $("#sensbut").click(function(event) {
  145. generateGraph(false, arrSensor[(event.target.text.split(" ")[1] - 1)], true);
  146. currentState = event.target.text.split(" ")[1];
  147. });
  148. }
  149. function generateGraph(flag, sensor, anim) {
  150. resize();
  151. if (flag) {
  152. // one plot for all sensors
  153. var length = 0;
  154. jQuery.each(sensor, function(index, tmp) {
  155. if(length < tmp.arrEEPROM.length) {
  156. length = tmp.arrEEPROM.length;
  157. }
  158. });
  159. var labels = Array();
  160. actHour = actTime.split(":")[0];
  161. for(var i = length; i > 0; i--) {
  162. labels.unshift(actHour + ":00");
  163. actHour = (actHour - 1).mod(24);
  164. }
  165. labels.push(actTime);
  166. var dataTemperature = Array();
  167. var dataHumidity = Array();
  168. var tmpDataTemperature = Array();
  169. var tmpDataHumidity = Array();
  170. jQuery.each(sensor, function(index, tmp) {
  171. for (var i = 0; i < (length - tmp.arrEEPROM.length); i++) {
  172. tmpDataTemperature.push([]);
  173. tmpDataHumidity.push([]);
  174. }
  175. jQuery.each(tmp.arrEEPROM, function(index, value) {
  176. tmpDataTemperature.push(value['T']);
  177. tmpDataHumidity.push(value['H']);
  178. });
  179. tmpDataTemperature.push(tmp.currentTemp);
  180. tmpDataHumidity.push(tmp.currentHum);
  181. var lineColor = getColor(index);
  182. dataTemperature.push({label: sensorTabName + " " + tmp.id, data: tmpDataTemperature, fill: false,
  183. borderWidth: 3, borderColor : lineColor,});
  184. dataHumidity.push({label: sensorTabName + " " + tmp.id, data: tmpDataHumidity, fill: false,
  185. borderWidth: 3, borderColor : lineColor,});
  186. tmpDataTemperature = [];
  187. tmpDataHumidity = [];
  188. });
  189. } else {
  190. // plot for one sensor
  191. var labels = Array();
  192. var tmpDataTemperature = Array();
  193. var tmpDataHumidity = Array();
  194. actHour = actTime.split(":")[0];
  195. actHour = (actHour - sensor.arrEEPROM.length).mod(24);
  196. jQuery.each(sensor.arrEEPROM, function(index, value) {
  197. actHour = (actHour + 1).mod(24);
  198. labels.push(actHour + ":00");
  199. tmpDataTemperature.push(value['T']);
  200. tmpDataHumidity.push(value['H']);
  201. });
  202. labels.push(actTime);
  203. tmpDataTemperature.push(sensor.currentTemp);
  204. tmpDataHumidity.push(sensor.currentHum);
  205. var dataTemperature = [{label: temperatureLabel, data: tmpDataTemperature,
  206. fill: false, borderWidth: 3, borderColor: singleChartTempColor,}];
  207. var dataHumidity = [{label: humidityLabel, data: tmpDataHumidity,
  208. fill: false, borderWidth: 3, borderColor: singleChartHumidColor,}];
  209. }
  210. var tempCtx = $('#temperatureChart');
  211. var humCtx = $('#humidityChart');
  212. var tempOptions = {
  213. title: {
  214. display: true,
  215. text: temperatureHeading
  216. },
  217. responsive: true,
  218. maintainAspectRatio: true,
  219. scaleOverride: true,
  220. };
  221. var humOptions = {
  222. title: {
  223. display: true,
  224. text: humidityHeading
  225. },
  226. responsive: true,
  227. maintainAspectRatio: true,
  228. scaleOverride: true,
  229. };
  230. if (!anim) {
  231. tempOptions.animation = false;
  232. humOptions.animation = false;
  233. }
  234. var tempChart = new Chart(tempCtx, {
  235. type: 'line',
  236. data: {
  237. labels: labels,
  238. datasets: dataTemperature,
  239. },
  240. options: tempOptions
  241. });
  242. var humCharts = new Chart(humCtx, {
  243. type: 'line',
  244. data: {
  245. labels: labels,
  246. datasets: dataHumidity,
  247. },
  248. options: humOptions
  249. });
  250. }
  251. // Modulo-Bug: http://javascript.about.com/od/problemsolving/a/modulobug.htm
  252. Number.prototype.mod = function(n) {
  253. return ((this%n)+n)%n;
  254. }
  255. function getColor(index) {
  256. if (index < preDefinedColors.length) {
  257. return preDefinedColors[index];
  258. } else {
  259. return getRandomColor();
  260. }
  261. }
  262. function getRandomColor() {
  263. var letters = '0123456789ABCDEF'.split('');
  264. var color = '#';
  265. for (var i = 0; i < 6; i++ ) {
  266. color += letters[Math.floor(Math.random() * 16)];
  267. }
  268. return color;
  269. }