Create global_json() for all and expanded the data to the complete setup. Added design for the global setup. default tip

Fri, 19 Apr 2024 20:56:55 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 19 Apr 2024 20:56:55 +0200
changeset 689
f94b525f7563
parent 688
8bf6389e59a2

Create global_json() for all and expanded the data to the complete setup. Added design for the global setup.

thermferm/mqtt.c file | annotate | diff | comparison | revisions
thermferm/mqtt.h file | annotate | diff | comparison | revisions
thermferm/server.c file | annotate | diff | comparison | revisions
www/devices.php file | annotate | diff | comparison | revisions
www/includes/global.inc.php file | annotate | diff | comparison | revisions
www/js/devices.js file | annotate | diff | comparison | revisions
www/js/set_devices.js file | annotate | diff | comparison | revisions
www/set_devices.php file | annotate | diff | comparison | revisions
--- a/thermferm/mqtt.c	Fri Apr 19 14:11:19 2024 +0200
+++ b/thermferm/mqtt.c	Fri Apr 19 20:56:55 2024 +0200
@@ -1409,9 +1409,9 @@
 }
 
 
-void node_ws(void)
+char *global_json(void)
 {
-    char		*payload = NULL, buf[64];
+    char		*payload, buf[64];
     struct utsname	ubuf;
 
     payload = xstrcpy((char *)"{\"type\":\"global\",\"name\":\"");
@@ -1428,26 +1428,79 @@
     }
     payload = xstrcat(payload, (char *)"\",\"FW\":\"");
     payload = xstrcat(payload, (char *)VERSION);
-    payload = xstrcat(payload, (char *)"\"");
+    payload = xstrcat(payload, (char *)"\",\"server_port\":");
+    sprintf(buf, "%d", Config.my_port);
+    payload = xstrcat(payload, buf);
+    payload = xstrcat(payload, (char *)",\"websocket_port\":");
+    sprintf(buf, "%d", Config.websocket_port);
+    payload = xstrcat(payload, buf);
 
     if (Config.temp_address || Config.hum_address) {
         payload = xstrcat(payload, (char *)",\"THB\":{");
         if (Config.temp_address) {
-            payload = xstrcat(payload, (char *)"\"temperature\":");
-            sprintf(buf, "%.1f", Config.temp_value / 1000.0);
+            payload = xstrcat(payload, (char *)"\"temperature\":{\"address\":\"");
+	    payload = xstrcat(payload, Config.temp_address);
+	    payload = xstrcat(payload, (char *)"\",\"state\":\"");
+	    payload = xstrcat(payload, (char *)TEMPSTATE[Config.temp_state]);
+	    payload = xstrcat(payload, (char *)"\",\"value\":");
+            sprintf(buf, "%d", Config.temp_value);
             payload = xstrcat(payload, buf);
+	    payload = xstrcat(payload, (char *)"}");
         }
         if (Config.temp_address && Config.hum_address)
             payload = xstrcat(payload, (char *)",");
         if (Config.hum_address) {
-            payload = xstrcat(payload, (char *)"\"humidity\":");
-            sprintf(buf, "%.1f", Config.hum_value / 1000.0);
+            payload = xstrcat(payload, (char *)"\"humidity\":{\"address\":\"");
+	    payload = xstrcat(payload, Config.hum_address);
+            payload = xstrcat(payload, (char *)"\",\"state\":\"");
+            payload = xstrcat(payload, (char *)TEMPSTATE[Config.hum_state]);
+            payload = xstrcat(payload, (char *)"\",\"value\":");
+            sprintf(buf, "%d", Config.hum_value);
             payload = xstrcat(payload, buf);
+	    payload = xstrcat(payload, (char *)"}");
         }
+	if (Config.temp_address || Config.hum_address)
+            payload = xstrcat(payload, (char *)",");
+	payload = xstrcat(payload, (char *)"\"index\":");
+	sprintf(buf, "%d", Config.temp_hum_idx);
+	payload = xstrcat(payload, buf);
         payload = xstrcat(payload, (char *)"}");
     }
+    payload = xstrcat(payload, (char *)",\"LCD\":{\"address\":");
+    sprintf(buf, "%d", Config.lcd_address);
+    payload = xstrcat(payload, buf);
+    payload = xstrcat(payload, (char *)",\"cols\":");
+    sprintf(buf, "%d", Config.lcd_cols);
+    payload = xstrcat(payload, buf);
+    payload = xstrcat(payload, (char *)",\"rows\":");
+    sprintf(buf, "%d", Config.lcd_rows);
+    payload = xstrcat(payload, buf);
+    payload = xstrcat(payload, (char *)"},\"MQTT\":{\"host\":\"");
+    payload = xstrcat(payload, Config.mqtt_host);
+    payload = xstrcat(payload, (char *)"\",\"port\":");
+    sprintf(buf, "%d", Config.mqtt_port);
+    payload = xstrcat(payload, buf);
+    if (Config.mqtt_username) {
+	payload = xstrcat(payload, (char *)",\"username\":\"");
+	payload = xstrcat(payload, Config.mqtt_username);
+	payload = xstrcat(payload, (char *)"\"");
+    	if (Config.mqtt_password) {
+	    payload = xstrcat(payload, (char *)",\"password\":\"");
+	    payload = xstrcat(payload, Config.mqtt_password);
+	    payload = xstrcat(payload, (char *)"\"");
+    	}
+    }
+    payload = xstrcat(payload, (char *)"}}");
+    return payload;
+}
 
-    payload = xstrcat(payload, (char *)"}");
+
+
+void node_ws(void)
+{
+    char	*payload = NULL;
+
+    payload = global_json();
     ws_broadcast(payload);
     free(payload);
     payload = NULL;
--- a/thermferm/mqtt.h	Fri Apr 19 14:11:19 2024 +0200
+++ b/thermferm/mqtt.h	Fri Apr 19 20:56:55 2024 +0200
@@ -49,6 +49,7 @@
 void mqtt_connect(void);
 void mqtt_disconnect(void);
 
+char *global_json(void);
 char *unit_data(units_list *unit, bool birth);
 
 /**
--- a/thermferm/server.c	Fri Apr 19 14:11:19 2024 +0200
+++ b/thermferm/server.c	Fri Apr 19 20:56:55 2024 +0200
@@ -674,43 +674,9 @@
     }
 
     if (strcmp(opt, (char *)"JSON") == 0) {
-	char		*payload = NULL, tbuf[64];
-	struct utsname	ubuf;
-
-    	payload = xstrcpy((char *)"{\"type\":\"global\",\"name\":\"");
-	payload = xstrcat(payload, Config.name);
-	payload = xstrcat(payload, (char *)"\",\"node\":\"");
-    	if (uname(&ubuf) == 0) {
-            payload = xstrcat(payload, ubuf.nodename);
-            payload = xstrcat(payload, (char *)"\",\"os\":\"");
-            payload = xstrcat(payload, ubuf.sysname);
-            payload = xstrcat(payload, (char *)"\",\"os_version\":\"");
-            payload = xstrcat(payload, ubuf.release);
-    	} else {
-            payload = xstrcat(payload, (char *)"Unknown\",\"os\":\"Unknown\",\"os_version\":\"Unknown");
-    	}
-    	payload = xstrcat(payload, (char *)"\",\"FW\":\"");
-    	payload = xstrcat(payload, (char *)VERSION);
-    	payload = xstrcat(payload, (char *)"\"");
+	char		*payload = NULL;
 
-    	if (Config.temp_address || Config.hum_address) {
-            payload = xstrcat(payload, (char *)",\"THB\":{");
-            if (Config.temp_address) {
-            	payload = xstrcat(payload, (char *)"\"temperature\":");
-            	sprintf(tbuf, "%.1f", Config.temp_value / 1000.0);
-            	payload = xstrcat(payload, tbuf);
-            }
-            if (Config.temp_address && Config.hum_address)
-            	payload = xstrcat(payload, (char *)",");
-            if (Config.hum_address) {
-            	payload = xstrcat(payload, (char *)"\"humidity\":");
-            	sprintf(tbuf, "%.1f", Config.hum_value / 1000.0);
-            	payload = xstrcat(payload, tbuf);
-            }
-            payload = xstrcat(payload, (char *)"}");
-    	}
-
-    	payload = xstrcat(payload, (char *)"}");
+	payload = global_json();
     	srv_send(s, (char *)"213 Global json data follows:");
 	srv_send(s, payload);
 	srv_send(s, (char *)".");
--- a/www/devices.php	Fri Apr 19 14:11:19 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-<?php
-require_once($_SERVER['DOCUMENT_ROOT'].'/includes/global.inc.php');
-page_header('Sensor devices', 'devices');
-?>
-
-   <div id="jqxgrid"></div>
-    <div style="margin-top: 30px;">
-    <div id="cellbegineditevent"></div>
-    <div style="margin-top: 10px;" id="cellendeditevent"></div>
-   </div>
-
-   <!-- Popup editor window. -->
-   <div id="popupWindow">
-    <div>Edit device</div>
-    <div style="overflow: hidden;">
-     <table style="width: 100%;">
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Uuid:</td>
-       <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="dev_uuid" readonly /></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Description:</td>
-       <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="dev_description" /></td>
-      </tr>
-      <tr>
-       <td colspan="6"><hr></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Device type:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_type"></div></td>
-       <td style="vertical-align: top; float: right; padding: 3px;">I/O direction:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_direction"></div></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Device value:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_value"></div></td>
-       <td style="vertical-align: top; float: right; padding: 3px;">Value offset:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_offset"></div></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Address:</td>
-       <td align="left" colspan="2" style="vertical-align: top; padding: 3px;"><input id="dev_address" /></td>
-       <td style="vertical-align: top; float: right; padding: 3px;">Subdevice:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_subdevice"></div></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Present:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_present"></div></td>
-       <td style="vertical-align: top; float: right; padding: 3px;">GPIO pin:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_gpiopin"></div></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">In use:</td>
-       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_inuse"></div></td>
-       <td style="vertical-align: top; float: right; padding: 3px;">Last change:</td>
-       <td align="left" colspan="2" style="vertical-align: top; padding: 3px;"><input id="dev_timestamp" readonly /></td>
-      </tr>
-      <tr>
-       <td style="vertical-align: top; float: right; padding: 3px;">Comment:</td>
-       <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="dev_comment" /></td>
-      </tr>
-      <tr><td colspan="6"></td></tr>
-      <tr>
-       <td style="padding-top: 20px;" align="right"><input type="button" id="Delete" value="Delete" /></td>
-       <td></td>
-       <td></td><td></td>
-       <td style="padding-top: 20px;" align="right"><input style="margin-right: 5px;" type="button" id="Save" value="Save" /></td>
-       <td style="padding-top: 20px;" align="left"><input id="Cancel" type="button" value="Cancel" /></td>
-      </tr>
-     </table>
-     <div style="float: right; margin-top: 290px; margin-bottom: 10px;">
-      <input style="margin-right: 595px;" type="button" id="Save"   value="Save" />
-     </div>
-    </div>
-   </div>
-
-<?php
-confirm_delete();
-page_footer();
-?>
--- a/www/includes/global.inc.php	Fri Apr 19 14:11:19 2024 +0200
+++ b/www/includes/global.inc.php	Fri Apr 19 20:56:55 2024 +0200
@@ -171,7 +171,7 @@
      <li style='width: 80px;'>Setup
       <ul style='width: 200px;'>
        <li><img style='float: left; margin-right: 5px;' src='images/preferences.png' /><a href="set_global.php">Global</a></li>
-       <li><img style='float: left; margin-right: 5px;' src='images/database.png' /><a href="devices.php">Devices</a></li>
+       <li><img style='float: left; margin-right: 5px;' src='images/database.png' /><a href="set_devices.php">Devices</a></li>
        <li><img style='float: left; margin-right: 5px;' src='images/fermenter.png' /><a href="set_fermenters.php">Fermenters</a></li>
        <li><img style='float: left; margin-right: 5px;' src='images/computer.png' /><a href="set_simulators.php">Simulators</a></li>
       </ul>
--- a/www/js/devices.js	Fri Apr 19 14:11:19 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2024
- *
- * Michiel Broek <mbroek at mbse dot eu>
- *
- * This file is part of mbsePi-apps
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * BrewCloud is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with ThermFerm; see the file COPYING.  If not, write to the Free
- * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *****************************************************************************/
-
-
-function createDelElements() {
- $('#eventWindow').jqxWindow({
-  theme: theme,
-  position: { x: 490, y: 210 },
-  width: 300,
-  height: 175,
-  resizable: false,
-  isModal: true,
-  modalOpacity: 0.4,
-  okButton: $('#delOk'),
-  cancelButton: $('#delCancel'),
-  initContent: function() {
-   $('#delOk').jqxButton({ template: 'danger', width: '65px', theme: theme });
-   $('#delCancel').jqxButton({ template: 'success', width: '65px', theme: theme });
-   $('#delCancel').focus();
-  }
- });
- $('#eventWindow').jqxWindow('hide');
-}
-
-
-$(document).ready(function() {
- var dataRecord = {},
- source = {
-  datatype: 'json',
-  cache: false,
-  datafields: [
-   { name: 'uuid', type: 'string' },
-   { name: 'type', type: 'string' },
-   { name: 'address', type: 'string' },
-   { name: 'subdevice', type: 'int' },
-   { name: 'inuse', type: 'int' },
-   { name: 'description', type: 'string' },
-   { name: 'direction', type: 'string' },
-   { name: 'value', type: 'int' },
-   { name: 'offset', type: 'int' },
-   { name: 'present', type: 'string' },
-   { name: 'gpiopin', type: 'int' },
-   { name: 'comment', type: 'string' },
-   { name: 'timestamp', type: 'int' }
-  ],
-  id: 'uuid',
-  url: 'getdevices.php'
- },
- dataAdapter = new $.jqx.dataAdapter(source),
- editrow = -1,
- tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
-
- // initialize the input fields.
- $('#dev_uuid').jqxInput({ theme: theme, width: 480, height: 23 });
- $('#dev_description').jqxInput({ theme: theme, width: 800, height: 23 });
- $('#dev_type').jqxDropDownList({
-  theme: theme,
-  source: DeviceTypeAdapter,
-  valueMember: 'mno',
-  displayMember: 'en',
-  width: 180,
-  height: 23,
-  autoDropDownHeight: true
- });
- $('#dev_direction').jqxDropDownList({
-  theme: theme,
-  source: DeviceDirectionAdapter,
-  valueMember: 'mno',
-  displayMember: 'en',
-  width: 180,
-  height: 23,
-  autoDropDownHeight: true
- });
- $('#dev_value').jqxNumberInput(Spin0dec);
- $('#dev_offset').jqxNumberInput(Spin0dec);
- $('#dev_address').jqxInput({ theme: theme, width: 200, height: 23 });
- $('#dev_subdevice').jqxNumberInput(SubInt);
- $('#dev_present').jqxDropDownList({
-  theme: theme,
-  source: DevicePresentAdapter,
-  valueMember: 'mno',
-  displayMember: 'en',
-  width: 180,
-  height: 23,
-  autoDropDownHeight: true
- });
- $('#dev_gpiopin').jqxNumberInput(GPIOInt);
- $('#dev_inuse').jqxNumberInput(Show0dec);
- $('#dev_timestamp').jqxInput({ theme: theme, width: 200, height: 23 });
- $('#dev_comment').jqxInput({ theme: theme, width: 800, height: 23 });
-
- // initialize jqxGrid
- $('#jqxgrid').jqxGrid({
-  width: 1280,
-  height: 630,
-  source: dataAdapter,
-  theme: theme,
-  showstatusbar: true,
-  renderstatusbar: function(statusbar) {
-   var rowCount = $("#jqxgrid").jqxGrid('getrows').length;
-   statusbar.append('<div style="float: left; margin: 8px; color: orange !important;">Total items: ' + rowCount + '</div>');
-   var container, addButton, impButton;
-   container = $('<div style="overflow: hidden; position: relative; margin: 5px;"></div>');
-   addButton = $('<div style="float: right; margin-right: 15px;"><img style="position: relative; margin-top: 2px;" ' +
-     'src="images/add.png"/><span style="margin-left: 4px; position: relative; top: -4px;">Nieuw</span></div>');
-   container.append(addButton);
-   statusbar.append(container);
-   addButton.jqxButton({ theme: theme, width: 90, height: 17 });
-   // add new row.
-   addButton.click(function(event) {
-    editrow = -1;
-    $('#popupWindow').jqxWindow({ position: { x: 110, y: 30 } });
-
-    dataRecord.uuid = '';
-    $('#popupWindow').jqxWindow('open');
-   });
-  },
-  columns: [
-   { text: 'Address', datafield: 'address', width: 200 },
-   { text: 'Subdevice', datafield: 'subdevice', width: 100 },
-   { text: 'Direction', datafield: 'direction', width: 120 },
-   { text: 'Value', datafield: 'value', width: 80 },
-   { text: 'Description', datafield: 'description' },
-   { text: 'Last change', datafield: 'timestamp', width: 200,
-     cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
-      var date = new Date((value * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " ");
-      return '<span style="margin: 3px; margin-top: 6px; float: left;">' +  date + '</span>';
-    }
-   },
-   { text: '', datafield: 'Edit', width: 100, align: 'center', columntype: 'button', cellsrenderer: function() {
-    return 'Edit';
-    }, buttonclick: function(row) {
-     // open the popup window when the user clicks a button.
-     editrow = row;
-     $('#popupWindow').jqxWindow({ position: { x: 110, y: 15 } });
-     dataRecord = $('#jqxgrid').jqxGrid('getrowdata', editrow);
-     $('#dev_uuid').val(dataRecord.uuid);
-     $('#dev_description').val(dataRecord.description);
-     $('#dev_type').val(dataRecord.type);
-     $('#dev_direction').val(dataRecord.direction);
-     $('#dev_value').val(dataRecord.value);
-     $('#dev_offset').val(dataRecord.offset);
-     $('#dev_address').val(dataRecord.address);
-     $('#dev_subdevice').val(dataRecord.subdevice);
-     $('#dev_present').val(dataRecord.present);
-     $('#dev_gpiopin').val(dataRecord.gpiopin);
-     $('#dev_inuse').val(dataRecord.inuse);
-     var date = new Date((dataRecord.timestamp * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " ");
-     $('#dev_timestamp').val(date);
-     $('#dev_comment').val(dataRecord.comment);
-     // show the popup window.
-     $('#popupWindow').jqxWindow('open');
-    }
-   }
-  ],
- });
-
- // initialize the popup window and buttons.
- $('#popupWindow').jqxWindow({
-  width: 1050,
-  height: 625,
-  resizable: false,
-  theme: theme,
-  isModal: true,
-  autoOpen: false,
-  cancelButton: $('#Cancel'),
-  modalOpacity: 0.40
- });
- $('#popupWindow').on('open', function() {
-  $('#dev_description').jqxInput('selectAll');
- });
- $('#Delete').jqxButton({ template: 'danger', width: '90px', theme: theme });
- $('#Delete').click(function() {
-  if (editrow >= 0) {
-   // Open a popup to confirm this action.
-   $('#eventWindow').jqxWindow('open');
-   $('#delOk').click(function() {
-    var rowID = $('#jqxgrid').jqxGrid('getrowid', editrow);
-    $('#jqxgrid').jqxGrid('deleterow', rowID);
-   });
-  }
-  $('#popupWindow').jqxWindow('hide');
- });
- $('#Cancel').jqxButton({ template: 'primary', width: '90px', theme: theme });
- $('#Save').jqxButton({ template: 'success', width: '90px', theme: theme });
- $('#Save').click(function() {
-  var row, rowID = -1;
-  if (editrow >= 0) {
-   rowID = $('#jqxgrid').jqxGrid('getrowid', editrow);
-  }
-  row = {
-   uuid: dataRecord.uuid,
-   type: $('#type').val()
-  };
-  if (editrow >= 0) {
-   $('#jqxgrid').jqxGrid('updaterow', rowID, row);
-  } else {
-   $('#jqxgrid').jqxGrid('addrow', null, row);
-  }
-  $('#popupWindow').jqxWindow('hide');
- });
- createDelElements();
-
- websocket.onmessage = function(evt) {
-  var msg = evt.data;
-  var obj = JSON.parse(msg);
-
-  if (obj.ping) {
-   websocket.send('{"pong":' + obj.ping + '}');
-  }
-
-  if (obj.type == 'device') {
-   // Use the message to trigger update.
-   $('#jqxgrid').jqxGrid('updatebounddata');
-  }
- }
-});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/www/js/set_devices.js	Fri Apr 19 20:56:55 2024 +0200
@@ -0,0 +1,250 @@
+/*****************************************************************************
+ * Copyright (C) 2024
+ *
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of mbsePi-apps
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * BrewCloud is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+
+function createDelElements() {
+ $('#eventWindow').jqxWindow({
+  theme: theme,
+  position: { x: 490, y: 210 },
+  width: 300,
+  height: 175,
+  resizable: false,
+  isModal: true,
+  modalOpacity: 0.4,
+  okButton: $('#delOk'),
+  cancelButton: $('#delCancel'),
+  initContent: function() {
+   $('#delOk').jqxButton({ template: 'danger', width: '65px', theme: theme });
+   $('#delCancel').jqxButton({ template: 'success', width: '65px', theme: theme });
+   $('#delCancel').focus();
+  }
+ });
+ $('#eventWindow').jqxWindow('hide');
+}
+
+
+$(document).ready(function() {
+ var dataRecord = {},
+ source = {
+  datatype: 'json',
+  cache: false,
+  datafields: [
+   { name: 'uuid', type: 'string' },
+   { name: 'type', type: 'string' },
+   { name: 'address', type: 'string' },
+   { name: 'subdevice', type: 'int' },
+   { name: 'inuse', type: 'int' },
+   { name: 'description', type: 'string' },
+   { name: 'direction', type: 'string' },
+   { name: 'value', type: 'int' },
+   { name: 'offset', type: 'int' },
+   { name: 'present', type: 'string' },
+   { name: 'gpiopin', type: 'int' },
+   { name: 'comment', type: 'string' },
+   { name: 'timestamp', type: 'int' }
+  ],
+  id: 'uuid',
+  url: 'getdevices.php'
+ },
+ dataAdapter = new $.jqx.dataAdapter(source),
+ editrow = -1,
+ tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
+
+ // initialize the input fields.
+ $('#dev_uuid').jqxInput({ theme: theme, width: 480, height: 23 });
+ $('#dev_description').jqxInput({ theme: theme, width: 800, height: 23 });
+ $('#dev_type').jqxDropDownList({
+  theme: theme,
+  source: DeviceTypeAdapter,
+  valueMember: 'mno',
+  displayMember: 'en',
+  width: 180,
+  height: 23,
+  autoDropDownHeight: true
+ });
+ $('#dev_direction').jqxDropDownList({
+  theme: theme,
+  source: DeviceDirectionAdapter,
+  valueMember: 'mno',
+  displayMember: 'en',
+  width: 180,
+  height: 23,
+  autoDropDownHeight: true
+ });
+ $('#dev_value').jqxNumberInput(Spin0dec);
+ $('#dev_offset').jqxNumberInput(Spin0dec);
+ $('#dev_address').jqxInput({ theme: theme, width: 200, height: 23 });
+ $('#dev_subdevice').jqxNumberInput(SubInt);
+ $('#dev_present').jqxDropDownList({
+  theme: theme,
+  source: DevicePresentAdapter,
+  valueMember: 'mno',
+  displayMember: 'en',
+  width: 180,
+  height: 23,
+  autoDropDownHeight: true
+ });
+ $('#dev_gpiopin').jqxNumberInput(GPIOInt);
+ $('#dev_inuse').jqxNumberInput(Show0dec);
+ $('#dev_timestamp').jqxInput({ theme: theme, width: 200, height: 23 });
+ $('#dev_comment').jqxInput({ theme: theme, width: 800, height: 23 });
+
+ // initialize jqxGrid
+ $('#jqxgrid').jqxGrid({
+  width: 1280,
+  height: 630,
+  source: dataAdapter,
+  theme: theme,
+  showstatusbar: true,
+  renderstatusbar: function(statusbar) {
+   var rowCount = $("#jqxgrid").jqxGrid('getrows').length;
+   statusbar.append('<div style="float: left; margin: 8px; color: orange !important;">Total items: ' + rowCount + '</div>');
+   var container, addButton, impButton;
+   container = $('<div style="overflow: hidden; position: relative; margin: 5px;"></div>');
+   addButton = $('<div style="float: right; margin-right: 15px;"><img style="position: relative; margin-top: 2px;" ' +
+     'src="images/add.png"/><span style="margin-left: 4px; position: relative; top: -4px;">Nieuw</span></div>');
+   container.append(addButton);
+   statusbar.append(container);
+   addButton.jqxButton({ theme: theme, width: 90, height: 17 });
+   // add new row.
+   addButton.click(function(event) {
+    editrow = -1;
+    $('#popupWindow').jqxWindow({ position: { x: 110, y: 30 } });
+    $('#dev_uuid').val('');
+    $('#dev_description').val('');
+    $('#dev_type').val('NA');
+    $('#dev_direction').val('UNDEF');
+    $('#dev_value').val(0);
+    $('#dev_offset').val(0);
+    $('#dev_address').val('');
+    $('#dev_subdevice').val(0);
+    $('#dev_present').val('UNDEF');
+    $('#dev_gpiopin').val(-1);
+    $('#dev_inuse').val(0);
+    var now = new Date();
+    var date = new Date(now - tzoffset).toISOString().slice(0, 19).replace("T", " ");
+    $('#dev_timestamp').val(date);
+    $('#dev_comment').val('');
+
+    $('#popupWindow').jqxWindow('open');
+   });
+  },
+  columns: [
+   { text: 'Address', datafield: 'address', width: 200 },
+   { text: 'Subdevice', datafield: 'subdevice', width: 100 },
+   { text: 'Direction', datafield: 'direction', width: 120 },
+   { text: 'Value', datafield: 'value', width: 80 },
+   { text: 'Description', datafield: 'description' },
+   { text: 'Last change', datafield: 'timestamp', width: 200,
+     cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
+      var date = new Date((value * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " ");
+      return '<span style="margin: 3px; margin-top: 6px; float: left;">' +  date + '</span>';
+    }
+   },
+   { text: '', datafield: 'Edit', width: 100, align: 'center', columntype: 'button', cellsrenderer: function() {
+    return 'Edit';
+    }, buttonclick: function(row) {
+     // open the popup window when the user clicks a button.
+     editrow = row;
+     $('#popupWindow').jqxWindow({ position: { x: 110, y: 15 } });
+     dataRecord = $('#jqxgrid').jqxGrid('getrowdata', editrow);
+     $('#dev_uuid').val(dataRecord.uuid);
+     $('#dev_description').val(dataRecord.description);
+     $('#dev_type').val(dataRecord.type);
+     $('#dev_direction').val(dataRecord.direction);
+     $('#dev_value').val(dataRecord.value);
+     $('#dev_offset').val(dataRecord.offset);
+     $('#dev_address').val(dataRecord.address);
+     $('#dev_subdevice').val(dataRecord.subdevice);
+     $('#dev_present').val(dataRecord.present);
+     $('#dev_gpiopin').val(dataRecord.gpiopin);
+     $('#dev_inuse').val(dataRecord.inuse);
+     var date = new Date((dataRecord.timestamp * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " ");
+     $('#dev_timestamp').val(date);
+     $('#dev_comment').val(dataRecord.comment);
+     // show the popup window.
+     $('#popupWindow').jqxWindow('open');
+    }
+   }
+  ],
+ });
+
+ // initialize the popup window and buttons.
+ $('#popupWindow').jqxWindow({
+  width: 1050,
+  height: 625,
+  resizable: false,
+  theme: theme,
+  isModal: true,
+  autoOpen: false,
+  cancelButton: $('#Cancel'),
+  modalOpacity: 0.40
+ });
+ $('#popupWindow').on('open', function() {
+  $('#dev_description').jqxInput('selectAll');
+ });
+ $('#Delete').jqxButton({ template: 'danger', width: '90px', theme: theme });
+ $('#Delete').click(function() {
+  if (editrow >= 0) {
+   // Open a popup to confirm this action.
+   $('#eventWindow').jqxWindow('open');
+   $('#delOk').click(function() {
+    var rowID = $('#jqxgrid').jqxGrid('getrowid', editrow);
+    $('#jqxgrid').jqxGrid('deleterow', rowID);
+   });
+  }
+  $('#popupWindow').jqxWindow('hide');
+ });
+ $('#Cancel').jqxButton({ template: 'primary', width: '90px', theme: theme });
+ $('#Save').jqxButton({ template: 'success', width: '90px', theme: theme });
+ $('#Save').click(function() {
+  var row, rowID = -1;
+  if (editrow >= 0) {
+   rowID = $('#jqxgrid').jqxGrid('getrowid', editrow);
+  }
+  row = {
+   uuid: dataRecord.uuid,
+   type: $('#type').val()
+  };
+  if (editrow >= 0) {
+   $('#jqxgrid').jqxGrid('updaterow', rowID, row);
+  } else {
+   $('#jqxgrid').jqxGrid('addrow', null, row);
+  }
+  $('#popupWindow').jqxWindow('hide');
+ });
+ createDelElements();
+
+ websocket.onmessage = function(evt) {
+  var msg = evt.data;
+  var obj = JSON.parse(msg);
+
+  if (obj.ping) {
+   websocket.send('{"pong":' + obj.ping + '}');
+  }
+
+  if (obj.type == 'device') {
+   // Use the message to trigger update.
+   $('#jqxgrid').jqxGrid('updatebounddata');
+  }
+ }
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/www/set_devices.php	Fri Apr 19 20:56:55 2024 +0200
@@ -0,0 +1,80 @@
+<?php
+require_once($_SERVER['DOCUMENT_ROOT'].'/includes/global.inc.php');
+page_header('Sensor devices', 'set_devices');
+?>
+
+   <div id="jqxgrid"></div>
+    <div style="margin-top: 30px;">
+    <div id="cellbegineditevent"></div>
+    <div style="margin-top: 10px;" id="cellendeditevent"></div>
+   </div>
+
+   <!-- Popup editor window. -->
+   <div id="popupWindow">
+    <div>Edit device</div>
+    <div style="overflow: hidden;">
+     <table style="width: 100%;">
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Uuid:</td>
+       <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="dev_uuid" readonly /></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Description:</td>
+       <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="dev_description" /></td>
+      </tr>
+      <tr>
+       <td colspan="6"><hr></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Device type:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_type"></div></td>
+       <td style="vertical-align: top; float: right; padding: 3px;">I/O direction:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_direction"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Device value:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_value"></div></td>
+       <td style="vertical-align: top; float: right; padding: 3px;">Value offset:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_offset"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Address:</td>
+       <td align="left" colspan="2" style="vertical-align: top; padding: 3px;"><input id="dev_address" /></td>
+       <td style="vertical-align: top; float: right; padding: 3px;">Subdevice:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_subdevice"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Present:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_present"></div></td>
+       <td style="vertical-align: top; float: right; padding: 3px;">GPIO pin:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_gpiopin"></div></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">In use:</td>
+       <td colspan="2" style="padding: 3px;"><div style="float: left;" id="dev_inuse"></div></td>
+       <td style="vertical-align: top; float: right; padding: 3px;">Last change:</td>
+       <td align="left" colspan="2" style="vertical-align: top; padding: 3px;"><input id="dev_timestamp" readonly /></td>
+      </tr>
+      <tr>
+       <td style="vertical-align: top; float: right; padding: 3px;">Comment:</td>
+       <td align="left" colspan="5" style="vertical-align: top; padding: 3px;"><input id="dev_comment" /></td>
+      </tr>
+      <tr><td colspan="6"></td></tr>
+      <tr>
+       <td style="padding-top: 20px;" align="right"><input type="button" id="Delete" value="Delete" /></td>
+       <td></td>
+       <td></td><td></td>
+       <td style="padding-top: 20px;" align="right"><input style="margin-right: 5px;" type="button" id="Save" value="Save" /></td>
+       <td style="padding-top: 20px;" align="left"><input id="Cancel" type="button" value="Cancel" /></td>
+      </tr>
+     </table>
+     <div style="float: right; margin-top: 290px; margin-bottom: 10px;">
+      <input style="margin-right: 595px;" type="button" id="Save"   value="Save" />
+     </div>
+    </div>
+   </div>
+
+<?php
+confirm_delete();
+page_footer();
+?>

mercurial