|
1 /***************************************************************************** |
|
2 * Copyright (C) 2024 |
|
3 * |
|
4 * Michiel Broek <mbroek at mbse dot eu> |
|
5 * |
|
6 * This file is part of mbsePi-apps |
|
7 * |
|
8 * This is free software; you can redistribute it and/or modify it |
|
9 * under the terms of the GNU General Public License as published by the |
|
10 * Free Software Foundation; either version 2, or (at your option) any |
|
11 * later version. |
|
12 * |
|
13 * BrewCloud is distributed in the hope that it will be useful, but |
|
14 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License |
|
19 * along with ThermFerm; see the file COPYING. If not, write to the Free |
|
20 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|
21 *****************************************************************************/ |
|
22 |
|
23 |
|
24 function createDelElements() { |
|
25 $('#eventWindow').jqxWindow({ |
|
26 theme: theme, |
|
27 position: { x: 430, y: 210 }, |
|
28 width: 420, |
|
29 height: 175, |
|
30 resizable: false, |
|
31 isModal: true, |
|
32 modalOpacity: 0.4, |
|
33 okButton: $('#delOk'), |
|
34 cancelButton: $('#delCancel'), |
|
35 initContent: function() { |
|
36 $('#delOk').jqxButton({ template: 'danger', width: '65px', theme: theme }); |
|
37 $('#delCancel').jqxButton({ template: 'success', width: '65px', theme: theme }); |
|
38 $('#delCancel').focus(); |
|
39 } |
|
40 }); |
|
41 $('#eventWindow').jqxWindow('hide'); |
|
42 } |
|
43 |
|
44 |
|
45 function createAddElements() { |
|
46 $('#addWindow').jqxWindow({ |
|
47 theme: theme, |
|
48 position: { x: 400, y: 210 }, |
|
49 width: 480, |
|
50 height: 180, |
|
51 resizable: false, |
|
52 isModal: true, |
|
53 modalOpacity: 0.4, |
|
54 okButton: $('#addOk'), |
|
55 cancelButton: $('#addCancel'), |
|
56 initContent: function() { |
|
57 $('#addOk').jqxButton({ template: 'success', width: '65px', theme: theme }); |
|
58 $('#addCancel').jqxButton({ template: 'primary', width: '65px', theme: theme }); |
|
59 $('#addCancel').focus(); |
|
60 } |
|
61 }); |
|
62 $('#addWindow').jqxWindow('hide'); |
|
63 } |
|
64 |
|
65 |
|
66 |
|
67 $(document).ready(function() { |
|
68 var dataRecord = {}, |
|
69 url = 'dbsimulators.php', |
|
70 source = { |
|
71 datatype: 'json', |
|
72 cache: false, |
|
73 datafields: [ |
|
74 { name: 'uuid', type: 'string' }, |
|
75 { name: 'name', type: 'string' }, |
|
76 { name: 'simno', type: 'int' }, |
|
77 { name: 'volume_air', type: 'int' }, |
|
78 { name: 'volume_beer', type: 'int' }, |
|
79 { name: 'room_tempaddress', map: 'room>tempaddress' }, |
|
80 { name: 'room_temperature', map: 'room>temperature', type: 'float' }, |
|
81 { name: 'room_humaddress', map: 'room>humaddress' }, |
|
82 { name: 'room_humidity', map: 'room>humidity', type: 'float' }, |
|
83 { name: 'air_address', map: 'air>address' }, |
|
84 { name: 'air_temperature', map: 'air>temperature', type: 'float' }, |
|
85 { name: 'air_present', map: 'air>present' }, |
|
86 { name: 'beer_address', map: 'beer>address' }, |
|
87 { name: 'beer_temperature', map: 'beer>temperature', type: 'float' }, |
|
88 { name: 'beer_present', map: 'beer>present' }, |
|
89 { name: 'beer_address2', map: 'beer2>address' }, |
|
90 { name: 'beer_temperature2', map: 'beer2>temperature', type: 'float' }, |
|
91 { name: 'beer_present2', map: 'beer2>present' }, |
|
92 { name: 'chiller_address', map: 'chiller>address' }, |
|
93 { name: 'chiller_temperature', map: 'chiller>temperature', type: 'float' }, |
|
94 { name: 'chiller_present', map: 'chiller>present' }, |
|
95 { name: 'cooler_address', map: 'cooler>address' }, |
|
96 { name: 'cooler_temp', map: 'cooler>temperature', type: 'float' }, |
|
97 { name: 'cooler_time', map: 'cooler>time', type: 'int' }, |
|
98 { name: 'cooler_size', map: 'cooler>size', type: 'float' }, |
|
99 { name: 'cooler_present', map: 'cooler>present' }, |
|
100 { name: 'cooler_power', map: 'cooler>power', type: 'int' }, |
|
101 { name: 'heater_address', map: 'heater>address' }, |
|
102 { name: 'heater_temp', map: 'heater>temperature', type: 'float' }, |
|
103 { name: 'heater_time', map: 'heater>time', type: 'int' }, |
|
104 { name: 'heater_size', map: 'heater>size', type: 'float' }, |
|
105 { name: 'heater_present', map: 'heater>present' }, |
|
106 { name: 'heater_power', map: 'heater>power', type: 'int' }, |
|
107 { name: 'fan_address', map: 'fan>address' }, |
|
108 { name: 'fan_present', map: 'fan>present' }, |
|
109 { name: 'fan_power', map: 'fan>power', type: 'int' }, |
|
110 { name: 'light_address', map: 'light>address' }, |
|
111 { name: 'light_present', map: 'light>present' }, |
|
112 { name: 'light_power', map: 'light>power', type: 'int' }, |
|
113 { name: 'frigo_isolation', type: 'float' }, |
|
114 { name: 'timestamp', type: 'int' } |
|
115 ], |
|
116 id: 'uuid', |
|
117 url: url |
|
118 }, |
|
119 dataAdapter = new $.jqx.dataAdapter(source), |
|
120 editrow = -1, |
|
121 tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds |
|
122 |
|
123 // initialize the input fields. |
|
124 $('#name').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
125 $('#simno').jqxNumberInput(Show0dec); |
|
126 $('#uuid').jqxInput({ theme: theme, width: 360, height: 23 }); |
|
127 $('#room_temperature,#room_humidity').jqxNumberInput(Perc1dec); |
|
128 $('#volume_air,#volume_beer').jqxNumberInput(PosInt); |
|
129 $('#frigo_isolation').jqxNumberInput(Spin3dec); |
|
130 $('#timestamp').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
131 |
|
132 $('#air_address,#beer_address,#beer_address2,#chiller_address,#cooler_address,#heater_address,#fan_address,#light_address').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
133 $('#air_temperature,#beer_temperature,#beer_temperature2,#chiller_temperature').jqxNumberInput(Show4dec); |
|
134 $('#air_present,#beer_present,#beer_present2,#chiller_present,#cooler_present,#heater_present,#fan_present,#light_present').jqxDropDownList({ |
|
135 theme: theme, |
|
136 source: DevicePresentAdapter, |
|
137 valueMember: 'mno', |
|
138 displayMember: 'en', |
|
139 width: 180, |
|
140 height: 23, |
|
141 autoDropDownHeight: true |
|
142 }); |
|
143 $('#cooler_power,#heater_power,#fan_power,#light_power').jqxNumberInput(Perc0); |
|
144 $('#cooler_temp,#heater_temp').jqxNumberInput(Spin1dec); |
|
145 $('#cooler_time,#heater_time').jqxNumberInput(PosInt); |
|
146 $('#cooler_size,#heater_size').jqxNumberInput(Spin4dec); |
|
147 |
|
148 // initialize jqxGrid |
|
149 $('#jqxgrid').jqxGrid({ |
|
150 width: 1280, |
|
151 height: 630, |
|
152 source: dataAdapter, |
|
153 theme: theme, |
|
154 showstatusbar: true, |
|
155 renderstatusbar: function(statusbar) { |
|
156 var rowCount = $("#jqxgrid").jqxGrid('getrows').length; |
|
157 statusbar.append('<div style="float: left; margin: 8px; color: orange !important;">Total items: ' + rowCount + '</div>'); |
|
158 var container, addButton; |
|
159 container = $('<div style="overflow: hidden; position: relative; margin: 5px;"></div>'); |
|
160 addButton = $('<div style="float: right; margin-right: 15px;"><img style="position: relative; margin-top: 2px;" ' + |
|
161 'src="images/add.png"/><span style="margin-left: 4px; position: relative; top: -4px;">New</span></div>'); |
|
162 container.append(addButton); |
|
163 statusbar.append(container); |
|
164 addButton.jqxButton({ theme: theme, width: 90, height: 17 }); |
|
165 // add new row. |
|
166 addButton.click(function(event) { |
|
167 $('#addWindow').jqxWindow('open'); |
|
168 $('#addName').jqxInput({ theme: theme, width: 180, height: 23 }); |
|
169 $('#addOk').click(function() { |
|
170 var data, |
|
171 data = 'add=true&name=' + $('#addName').val(); |
|
172 console.log(data); |
|
173 $.ajax({ |
|
174 dataType: 'json', |
|
175 url: url, |
|
176 cache: false, |
|
177 data: data, |
|
178 type: 'POST', |
|
179 success: function(data) { |
|
180 if (data.error) { |
|
181 console.log('add: ' + data.msg); |
|
182 alert('Error: ' + data.msg); |
|
183 } else { |
|
184 console.log('add: success'); |
|
185 } |
|
186 }, |
|
187 error: function(jqXHR, textStatus, errorThrown) {} |
|
188 }); |
|
189 $('#jqxgrid').jqxGrid('updatebounddata'); |
|
190 }); |
|
191 }); |
|
192 }, |
|
193 columns: [ |
|
194 { text: 'Name', datafield: 'name' }, |
|
195 { text: 'No.', datafield: 'simno', width: 80 }, |
|
196 { text: 'Air temp', datafield: 'air_temperature', width: 100 }, |
|
197 { text: 'Beer temp', datafield: 'beer_temperature', width: 100 }, |
|
198 { text: 'Heater', datafield: 'heater_power', width: 80 }, |
|
199 { text: 'Cooler', datafield: 'cooler_power', width: 80 }, |
|
200 { text: 'Fan', datafield: 'fan_power', width: 80 }, |
|
201 { text: 'Last change', datafield: 'timestamp', width: 190, |
|
202 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { |
|
203 var date = new Date((value * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " "); |
|
204 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + date + '</span>'; |
|
205 } |
|
206 }, |
|
207 { text: '', datafield: 'Edit', width: 100, align: 'center', columntype: 'button', cellsrenderer: function() { |
|
208 return 'Edit'; |
|
209 }, buttonclick: function(row) { |
|
210 // open the popup window when the user clicks a button. |
|
211 editrow = row; |
|
212 $('#popupWindow').jqxWindow({ position: { x: 40, y: 15 } }); |
|
213 dataRecord = $('#jqxgrid').jqxGrid('getrowdata', editrow); |
|
214 $('#name').val(dataRecord.name); |
|
215 $('#uuid').val(dataRecord.uuid); |
|
216 $('#simno').val(dataRecord.simno); |
|
217 $('#room_temperature').val(dataRecord.room_temperature); |
|
218 $('#room_humidity').val(dataRecord.room_humidity); |
|
219 $('#volume_air').val(dataRecord.volume_air); |
|
220 $('#volume_beer').val(dataRecord.volume_beer); |
|
221 $('#frigo_isolation').val(dataRecord.frigo_isolation); |
|
222 |
|
223 $('#air_address').val(dataRecord.air_address); |
|
224 $('#air_temperature').val(dataRecord.air_temperature); |
|
225 $('#air_present').val(dataRecord.air_present); |
|
226 $('#beer_address').val(dataRecord.beer_address); |
|
227 $('#beer_temperature').val(dataRecord.beer_temperature); |
|
228 $('#beer_present').val(dataRecord.beer_present); |
|
229 $('#beer_address2').val(dataRecord.beer_address2); |
|
230 $('#beer_temperature2').val(dataRecord.beer_temperature2); |
|
231 $('#beer_present2').val(dataRecord.beer_present2); |
|
232 $('#chiller_address').val(dataRecord.chiller_address); |
|
233 $('#chiller_temperature').val(dataRecord.chiller_temperature); |
|
234 $('#chiller_present').val(dataRecord.chiller_present); |
|
235 $('#cooler_address').val(dataRecord.cooler_address); |
|
236 $('#cooler_power').val(dataRecord.cooler_power); |
|
237 $('#cooler_present').val(dataRecord.cooler_present); |
|
238 $('#cooler_temp').val(dataRecord.cooler_temp); |
|
239 $('#cooler_time').val(dataRecord.cooler_time); |
|
240 $('#cooler_size').val(dataRecord.cooler_size); |
|
241 $('#heater_address').val(dataRecord.heater_address); |
|
242 $('#heater_power').val(dataRecord.heater_power); |
|
243 $('#heater_present').val(dataRecord.heater_present); |
|
244 $('#heater_temp').val(dataRecord.heater_temp); |
|
245 $('#heater_time').val(dataRecord.heater_time); |
|
246 $('#heater_size').val(dataRecord.heater_size); |
|
247 $('#fan_address').val(dataRecord.fan_address); |
|
248 $('#fan_power').val(dataRecord.fan_power); |
|
249 $('#fan_present').val(dataRecord.fan_present); |
|
250 $('#light_address').val(dataRecord.light_address); |
|
251 $('#light_power').val(dataRecord.light_power); |
|
252 $('#light_present').val(dataRecord.light_present); |
|
253 var date = new Date((dataRecord.timestamp * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " "); |
|
254 $('#timestamp').val(date); |
|
255 // show the popup window. |
|
256 $('#popupWindow').jqxWindow('open'); |
|
257 } |
|
258 } |
|
259 ], |
|
260 }); |
|
261 |
|
262 // initialize the popup window and buttons. |
|
263 $('#popupWindow').jqxWindow({ |
|
264 width: 1280, |
|
265 height: 625, |
|
266 resizable: false, |
|
267 theme: theme, |
|
268 isModal: true, |
|
269 autoOpen: false, |
|
270 cancelButton: $('#Cancel'), |
|
271 modalOpacity: 0.40 |
|
272 }); |
|
273 $('#popupWindow').on('open', function() { |
|
274 $('#dev_description').jqxInput('selectAll'); |
|
275 }); |
|
276 $('#Delete').jqxButton({ template: 'danger', width: '90px', theme: theme }); |
|
277 $('#Delete').click(function() { |
|
278 if (editrow >= 0) { |
|
279 // Open a popup to confirm this action. |
|
280 $('#eventWindow').jqxWindow('open'); |
|
281 $('#delOk').click(function() { |
|
282 var data, |
|
283 data = 'del=true&uuid=' + $('#dev_uuid').val(); |
|
284 $.ajax({ |
|
285 dataType: 'json', |
|
286 url: url, |
|
287 cache: false, |
|
288 data: data, |
|
289 type: 'POST', |
|
290 success: function(data) { |
|
291 if (data.error) { |
|
292 console.log('del: ' + data.msg); |
|
293 alert('Error: ' + data.msg); |
|
294 } else { |
|
295 console.log('del: success'); |
|
296 } |
|
297 }, |
|
298 error: function(jqXHR, textStatus, errorThrown) {} |
|
299 }); |
|
300 $('#jqxgrid').jqxGrid('updatebounddata'); |
|
301 }); |
|
302 } |
|
303 $('#popupWindow').jqxWindow('hide'); |
|
304 }); |
|
305 $('#Cancel').jqxButton({ template: 'primary', width: '90px', theme: theme }); |
|
306 $('#Save').jqxButton({ template: 'success', width: '90px', theme: theme }); |
|
307 $('#Save').click(function() { |
|
308 var data, |
|
309 row = { |
|
310 uuid: dataRecord.uuid, |
|
311 type: $('#dev_type').val(), |
|
312 direction: $('#dev_direction').val(), |
|
313 value: parseInt($('#dev_value').jqxNumberInput('decimal')), |
|
314 offset: parseInt($('#dev_offset').jqxNumberInput('decimal')), |
|
315 present: $('#dev_present').val(), |
|
316 address: $('#dev_address').val(), |
|
317 subdevice: parseInt($('#dev_subdevice').jqxNumberInput('decimal')), |
|
318 gpiopin: parseInt($('#dev_gpiopin').jqxNumberInput('val')), |
|
319 description: $('#dev_description').val(), |
|
320 comment: $('#dev_comment').val() |
|
321 }; |
|
322 data = 'update=true&' + $.param(row); |
|
323 console.log(data); |
|
324 $.ajax({ |
|
325 dataType: 'json', |
|
326 url: url, |
|
327 cache: false, |
|
328 data: data, |
|
329 type: 'POST', |
|
330 success: function(data) { |
|
331 if (data.error) { |
|
332 console.log('update: ' + data.msg); |
|
333 alert('Error: ' + data.msg); |
|
334 } else { |
|
335 console.log('update: success'); |
|
336 } |
|
337 }, |
|
338 error: function(jqXHR, textStatus, errorThrown) {} |
|
339 }); |
|
340 $('#popupWindow').jqxWindow('hide'); |
|
341 }); |
|
342 createDelElements(); |
|
343 createAddElements(); |
|
344 |
|
345 websocket.onmessage = function(evt) { |
|
346 var msg = evt.data; |
|
347 var obj = JSON.parse(msg); |
|
348 |
|
349 if (obj.ping) { |
|
350 websocket.send('{"pong":' + obj.ping + '}'); |
|
351 } |
|
352 |
|
353 if (obj.type == 'simulator') { |
|
354 // Use the message to trigger update. |
|
355 $('#jqxgrid').jqxGrid('updatebounddata'); |
|
356 } |
|
357 } |
|
358 }); |