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

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