ESP8266 SHT21 sensor
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

client-script.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. var arrSensor = Array(); // Data received from Websockets
  13. // Text Strings. Change these to translate.
  14. textAvailableSensors = "Available Sensors";
  15. textButtonNext = "Continue";
  16. homeTabName = "Home";
  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. // Draw initial view when the page has been loaded
  34. $(document).ready(initialView);
  35. function initialView() {
  36. $('#contentDiv').empty();
  37. $('#contentDiv').append(`<div class="col-sm-12 col-md-12 col-lg-12">
  38. <div class="panel panel-primary">
  39. <div class="panel-heading" id="listSensorsHeading">
  40. ` + textAvailableSensors + ` (0/0)
  41. </div>
  42. <div class="panel-body">
  43. <ul class="list-group" id="listSensors"></ul>
  44. <div id="alertDiv"></div>
  45. <button class="btn btn-primary" disabled="" id="btnSubmit">
  46. ` + textButtonNext + `
  47. </button>
  48. </div>
  49. </div>
  50. </div>`);
  51. $('#listSensorsHeading').empty();
  52. $('#listSensorsHeading').html(textAvailableSensors + " (0/" + clients.length + ")");
  53. // Iterate all given client IPs and get their data using Websocket
  54. var count = [0];
  55. jQuery.each(clients, function(index, client) {
  56. webSocket(client, "2391", count, clients.length);
  57. });
  58. // Button to continue to graph view
  59. $("#btnSubmit").click(function(event) {
  60. $('#contentDiv').empty();
  61. generateView(arrSensor);
  62. });
  63. }
  64. function webSocket(wsUri, wsPort, count, clientsCount) {
  65. websocket = new WebSocket("ws://" + wsUri + ":" + wsPort + "/");
  66. websocket.onopen = function(evt) {};
  67. websocket.onclose = function(evt) {};
  68. websocket.onmessage = function(evt) {
  69. var jsonData = jQuery.parseJSON(evt.data);
  70. count[0]++;
  71. var sensor = {id: count[0], ip: wsUri, currentTemp: jsonData['T'], currentHum: jsonData['H']};
  72. var arrEEPROM = Array();
  73. jQuery.each(jsonData['EEPROM'], function(index, data) {
  74. arrEEPROM.push(data);
  75. });
  76. sensor.arrEEPROM = arrEEPROM;
  77. arrSensor.push(sensor);
  78. $('#listSensorsHeading').html(textAvailableSensors + " (" + sensor.id + "/" + clientsCount + ")");
  79. $('#listSensors').append('<li class="list-group-item">' +
  80. ' Sensor ' + sensor.id +
  81. ' | IP: ' + sensor.ip +
  82. ' | Temperature: ' + sensor.currentTemp +
  83. ' | Humidity: ' + sensor.currentHum +
  84. '</li>');
  85. // Enable continue buttons when all modules have been reached
  86. if(count[0] == clientsCount) {
  87. $('#btnSubmit').prop("disabled", false);
  88. }
  89. };
  90. websocket.onerror = function(evt) {
  91. if($('#websocketError').length ) {
  92. $('.alert-danger').append(errorMessage + wsUri + '<br>');
  93. } else {
  94. $('#alertDiv').append('<div class="alert alert-danger" id="websocketError">' +
  95. '<strong>' + errorTitle
  96. + '</strong><br>' + errorMessage
  97. + wsUri + '<br></div>');
  98. }
  99. console.log(evt.data);
  100. };
  101. }
  102. function generateView(arrSensor) {
  103. $('#contentDiv').append(`<div class="col-sm-12 col-md-12 col-lg-12">
  104. <div class="panel panel-primary">
  105. <ul class="nav nav-pills">
  106. <li class="active"><a class="navtab" data-toggle="tab" href="#home">` + homeTabName + `</a></li>
  107. </ul>
  108. <div class="panel-body">
  109. <div id="contentPanel">
  110. </div>
  111. </div>
  112. </div>
  113. </div>`);
  114. jQuery.each(arrSensor, function(index, sensor) {
  115. $('.nav-pills').append('<li><a class="navtab" data-toggle="tab" href="#' + sensor.id + '">' + sensorTabName + ' ' + sensor.id + '</a></li>');
  116. });
  117. // flag for combined plot -> true
  118. generateGraph(true, arrSensor);
  119. $(".navtab").click(function(event) {
  120. $('#contentPanel').empty();
  121. if(event.target.text == homeTabName) {
  122. // flag for combined plot -> true
  123. generateGraph(true, arrSensor);
  124. } else {
  125. generateGraph(false, arrSensor[(event.target.text.split(" ")[1] - 1)]);
  126. }
  127. });
  128. }
  129. function generateGraph(flag, sensor) {
  130. $('#contentPanel').append(`<div class="row">
  131. <div class="col-sm-12 col-md-12 col-lg-6">
  132. <div id="temperatureDiv" class="embed-responsive embed-responsive-4by3">
  133. <canvas id="temperatureChart"></canvas>
  134. </div>
  135. </div>
  136. <div class="col-sm-12 col-md-12 col-lg-6">
  137. <div id="humidityDiv" class="embed-responsive embed-responsive-4by3">
  138. <canvas id="humidityChart"></canvas>
  139. </div>
  140. </div>
  141. </div>`);
  142. if (flag) {
  143. // one plot for all sensors
  144. var length = 0;
  145. jQuery.each(sensor, function(index, tmp) {
  146. if(length < tmp.arrEEPROM.length) {
  147. length = tmp.arrEEPROM.length;
  148. }
  149. });
  150. var labels = Array();
  151. actHour = actTime.split(":")[0];
  152. for(var i = length; i > 0; i--) {
  153. labels.unshift(actHour + ":00");
  154. actHour = (actHour - 1).mod(24);
  155. }
  156. labels.push(actTime);
  157. var dataTemperature = Array();
  158. var dataHumidity = Array();
  159. var tmpDataTemperature = Array();
  160. var tmpDataHumidity = Array();
  161. jQuery.each(sensor, function(index, tmp) {
  162. for (var i = 0; i < (length - tmp.arrEEPROM.length); i++) {
  163. tmpDataTemperature.push([]);
  164. tmpDataHumidity.push([]);
  165. }
  166. jQuery.each(tmp.arrEEPROM, function(index, value) {
  167. tmpDataTemperature.push(value['T']);
  168. tmpDataHumidity.push(value['H']);
  169. });
  170. tmpDataTemperature.push(tmp.currentTemp);
  171. tmpDataHumidity.push(tmp.currentHum);
  172. var lineColor = getColor(index);
  173. dataTemperature.push({label: sensorTabName + " " + tmp.id, data: tmpDataTemperature, fill: false,
  174. borderWidth: 3, borderColor : lineColor,});
  175. dataHumidity.push({label: sensorTabName + " " + tmp.id, data: tmpDataHumidity, fill: false,
  176. borderWidth: 3, borderColor : lineColor,});
  177. tmpDataTemperature = [];
  178. tmpDataHumidity = [];
  179. });
  180. } else {
  181. // plot for one sensor
  182. var labels = Array();
  183. var tmpDataTemperature = Array();
  184. var tmpDataHumidity = Array();
  185. actHour = actTime.split(":")[0];
  186. actHour = (actHour - sensor.arrEEPROM.length).mod(24);
  187. jQuery.each(sensor.arrEEPROM, function(index, value) {
  188. actHour = (actHour + 1).mod(24);
  189. labels.push(actHour + ":00");
  190. tmpDataTemperature.push(value['T']);
  191. tmpDataHumidity.push(value['H']);
  192. });
  193. labels.push(actTime);
  194. tmpDataTemperature.push(sensor.currentTemp);
  195. tmpDataHumidity.push(sensor.currentHum);
  196. var dataTemperature = [{label: temperatureLabel, data: tmpDataTemperature,
  197. fill: false, borderWidth: 3, borderColor: singleChartTempColor,}];
  198. var dataHumidity = [{label: humidityLabel, data: tmpDataHumidity,
  199. fill: false, borderWidth: 3, borderColor: singleChartHumidColor,}];
  200. }
  201. var tempCtx = $('#temperatureChart');
  202. var humCtx = $('#humidityChart');
  203. //tempCtx.attr('width', $('#temperatureDiv').width());
  204. //tempCtx.attr('height', $('#temperatureDiv').height());
  205. //humCtx.attr('width', $('#humidityDiv').width());
  206. //humCtx.attr('height', $('#humidityDiv').height());
  207. var tempChart = new Chart(tempCtx, {
  208. type: 'line',
  209. data: {
  210. labels: labels,
  211. datasets: dataTemperature,
  212. },
  213. options: {
  214. title: {
  215. display: true,
  216. text: temperatureHeading
  217. },
  218. responsive: true,
  219. maintainAspectRatio: true,
  220. scaleOverride: true
  221. }
  222. });
  223. var humCharts = new Chart(humCtx, {
  224. type: 'line',
  225. data: {
  226. labels: labels,
  227. datasets: dataHumidity,
  228. },
  229. options: {
  230. title: {
  231. display: true,
  232. text: humidityHeading
  233. },
  234. responsive: true,
  235. maintainAspectRatio: true,
  236. scaleOverride: true
  237. }
  238. });
  239. }
  240. // Modulo-Bug: http://javascript.about.com/od/problemsolving/a/modulobug.htm
  241. Number.prototype.mod = function(n) {
  242. return ((this%n)+n)%n;
  243. }
  244. function getColor(index) {
  245. if (index < preDefinedColors.length) {
  246. return preDefinedColors[index];
  247. } else {
  248. return getRandomColor();
  249. }
  250. }
  251. function getRandomColor() {
  252. var letters = '0123456789ABCDEF'.split('');
  253. var color = '#';
  254. for (var i = 0; i < 6; i++ ) {
  255. color += letters[Math.floor(Math.random() * 16)];
  256. }
  257. return color;
  258. }