Sat, 19 Jan 2019 12:05:37 +0100
In bmsd added missing json percent. The Makefile didn't install the fpdf library. Added profile commands. Small changes to the monitor fermenters screen. The monitor fermenters scheduler is now more responsive. Profiles selection and commands in the remote thermferm.
--- a/.hgignore Sat Jan 12 20:18:54 2019 +0100 +++ b/.hgignore Sat Jan 19 12:05:37 2019 +0100 @@ -9,6 +9,7 @@ doc/bms.pdf www/version.php www/config.php +www/thermferm www/run/sequence syntax: glob
--- a/bmsd/fermenters.c Sat Jan 12 20:18:54 2019 +0100 +++ b/bmsd/fermenters.c Sat Jan 19 12:05:37 2019 +0100 @@ -3,7 +3,7 @@ * @brief Handle fermenters status * @author Michiel Broek <mbroek at mbse dot eu> * - * Copyright (C) 2018 + * Copyright (C) 2018-2019 * * This file is part of the bms (Brewery Management System) * @@ -271,6 +271,9 @@ free(fermenter->profile_state); fermenter->profile_state = xstrcpy((char *)json_object_get_string(val)); } + if (json_object_object_get_ex(sensor, "percent", &val)) { + fermenter->profile_percent = json_object_get_int(val); + } if (json_object_object_get_ex(sensor, "inittemp", &temp)) { if (json_object_object_get_ex(temp, "low", &val)) { fermenter->profile_inittemp_low = json_object_get_double(val);
--- a/www/Makefile Sat Jan 12 20:18:54 2019 +0100 +++ b/www/Makefile Sat Jan 19 12:05:37 2019 +0100 @@ -30,7 +30,8 @@ rm -f version.php install: - ${INSTALL} -d -g 314 -o 314 ${PREFIX} ${WWWDIR} ${WWWDIR}/css \ + ${INSTALL} -d -g 314 -o 314 ${PREFIX} ${WWWDIR} ${WWWDIR}/css ${WWWDIR}/fpdf \ + ${WWWDIR}/fpdf/font \ ${WWWDIR}/jqwidgets ${WWWDIR}/js ${WWWDIR}/images/ ${WWWDIR}/includes/ ${INSTALL} -d -g 314 -o 314 -m 0777 ${WWWDIR}/run ${INSTALL} -g 314 -o 314 ${SRC} ${WWWDIR}/ @@ -40,6 +41,8 @@ ${INSTALL} -g 314 -o 314 includes/* ${WWWDIR}/includes/ cp -r jqwidgets/* ${WWWDIR}/jqwidgets/ chown -R 314:314 ${WWWDIR}/jqwidgets + cp -r fpdf/* ${WWWDIR}/fpdf/ + chown -R 314:314 ${WWWDIR}/fpdf ${INSTALL} -g 314 -o 314 js/* ${WWWDIR}/js/ filelist: Makefile
--- a/www/cmd_fermenter.php Sat Jan 12 20:18:54 2019 +0100 +++ b/www/cmd_fermenter.php Sat Jan 19 12:05:37 2019 +0100 @@ -44,6 +44,7 @@ * {"profile":{"uuid":"...","name":"profielnaam","inittemp":{"low":18.2,"high":20.5},"fridgemode":0, * "steps":[{"resttime":12,"steptime":36,"target":{"low":20.8,"high":23.1},"fridgemode":0}, * {"resttime":48,"steptime":48,"target":{"low":27.5,"high":28.0},"fridgemode":0}]}} + * {"profile":{"command":"start/stop/pause/abort"} */ $topic = "mbv1.0/fermenters/DCMD/" . $node . "/" . $alias; $payload = '\'{"timestamp":' . time() . ',"seq":' . $nr . ',"metric":' . $payload . '}\'';
--- a/www/css/style.css Sat Jan 12 20:18:54 2019 +0100 +++ b/www/css/style.css Sat Jan 19 12:05:37 2019 +0100 @@ -53,7 +53,7 @@ #fermenter_table { width: 960px; - height: 200px; + height: 210px; background: #252526; margin: 5px; border: 2px solid; @@ -96,6 +96,7 @@ float: left; background-color: #252526; margin: 5px; + margin-top: 3px; border: 2px solid; border-color: #59b4d4; border-radius: 5px 5px 5px 5px; @@ -125,7 +126,7 @@ */ #fermenter_panel_top { width: 290px; - height: 200px; + height: 100px; float: right; margin: 5px; background-color: #252526; @@ -142,25 +143,25 @@ height: 30px; float: left; text-align: center; - margin-top: 10px; + margin-top: 15px; margin-left: 20px; } #fermenter_panel_display { width: 290px; - height: 70px; + height: 98px; float: right; margin: 5px; + margin-top: 3px; background-color: #252526; border: 2px solid; border-color: #59b4d4; border-radius: 5px 5px 5px 5px; - margin-bottom: 3px; } #fermenter_display { width: 145px; - height: 70px; + height: 98px; float: left; text-align: center; } @@ -168,14 +169,14 @@ #fermenter_panel_control { width: 290px; - height: 140px; + height: 150px; float: right; margin: 5px; + margin-top: 3px; background-color: #252526; border: 2px solid; border-color: #59b4d4; border-radius: 5px 5px 5px 5px; - margin-bottom: 3px; } #fermenter_led1, @@ -185,7 +186,7 @@ height: 30px; float: left; text-align: center; - margin-top: 8px; + margin-top: 13px; } #fermenter_toggle1 { @@ -204,9 +205,10 @@ #fermenter_panel_buttons { width: 290px; - height: 155px; + height: 227px; float: right; margin: 5px; + margin-top: 3px; background-color: #252526; border: 2px solid; border-color: #59b4d4;
--- a/www/includes/db_profile_fermentation.php Sat Jan 12 20:18:54 2019 +0100 +++ b/www/includes/db_profile_fermentation.php Sat Jan 19 12:05:37 2019 +0100 @@ -26,11 +26,9 @@ if (isset($_GET['uuid']) && (strlen($_GET['uuid']) == 36)) { $sql .= "uuid='" . $_GET['uuid']; -// syslog(LOG_NOTICE, 'Keep uuid '); } else { $uuid = str_replace("\n", "", file_get_contents('/proc/sys/kernel/random/uuid')); $sql .= "uuid='" . $uuid; -// syslog(LOG_NOTICE, 'New uuid '); } $sql .= "', name='" . mysqli_real_escape_string($connect, $_GET['name']); @@ -107,7 +105,7 @@ $profiles .= '}'; } $profiles .= ']'; -// syslog(LOG_NOTICE, $profiles); + syslog(LOG_NOTICE, $profiles); header("Content-type: application/json"); echo $profiles; }
--- a/www/js/mon_fermenter.js Sat Jan 12 20:18:54 2019 +0100 +++ b/www/js/mon_fermenter.js Sat Jan 19 12:05:37 2019 +0100 @@ -25,10 +25,12 @@ var record = {}; var blank = {}; + var ppayload = ''; var newBase = false; var newProduct = false; var newSwitch = false; var newProfile = false; + var schedule = 0; var yl = 12; // Normal yeast temp range var yh = 24; @@ -53,8 +55,7 @@ data.push(blank); for (var i = 0; i < records.length; i++) { var row = records[i]; - if (row.inventory || ! fermentableinstock) - data.push(row); + data.push(row); } return data; }, @@ -68,7 +69,7 @@ source: productlist, displayMember: "code", width: 150, - height: 23, + height: 24, dropDownWidth: 500, autoDropDownHeight: true, renderer: function (index, label, value) { @@ -77,6 +78,59 @@ } }); + var profileSource = { + datatype: "json", + cache: false, + datafields: [ + { name: 'record', type: 'int' }, + { name: 'uuid', type: 'string' }, + { name: 'name', type: 'string' }, + { name: 'inittemp_lo', type: 'float' }, + { name: 'inittemp_hi', type: 'float' }, + { name: 'fridgemode', type: 'int' }, + { name: 'totalsteps', type: 'int' }, + { name: 'duration', type: 'int' }, + { name: 'steps', type: 'array' } + ], + id: 'record', + url: "includes/db_profile_fermentation.php" + }; + var profilelist = new $.jqx.dataAdapter(profileSource, { + beforeLoadComplete: function (records) { + var data = new Array(); + var empty = {}; + // Create a dummy beer on top to store in idle fermenters. + empty['record'] = -1; + empty['uuid'] = ''; + empty['name'] = 'Wis profiel'; + empty['inittemp_lo'] = 20; + empty['inittemp_hi'] = 20; + empty['fridgemode'] = 0; + empty['totalsteps'] = 0; + empty['duration'] = 0; + empty['steps'] = '[]'; + data.push(empty); + for (var i = 0; i < records.length; i++) { + var row = records[i]; + data.push(row); + } + return data; + }, + loadError: function(jqXHR, status, error) { + $('#err').text(status + ' ' + error); + }, + }); + $("#select_profile").jqxDropDownList({ + placeHolder: "Kies profiel:", + theme: theme, + source: profilelist, + displayMember: "name", + width: 150, + height: 24, + dropDownWidth: 500, + autoDropDownHeight: true, + }); + var gaugeoptions = { min: 0, max: 40, width: 375, height: 375, ranges: [{ startValue: 0, endValue: yl, style: { fill: '#3399FF', stroke: '#3399FF' }, endWidth: 10, startWidth: 10 }, @@ -123,15 +177,14 @@ srcMode = [ "OFF", "NONE", "FRIDGE", "BEER", "PROFILE" ]; srcStage = [ "PRIMARY", "SECONDARY", "TERTIARY", "CARBONATION" ]; - $("#info_mode").jqxDropDownList({ theme: theme, source: srcMode, width: 100, height: 23, dropDownHeight: 156 }); - $("#info_stage").jqxDropDownList({ theme: theme, source: srcStage, width: 150, height: 23, dropDownHeight: 125 }); + $("#info_mode").jqxDropDownList({ theme: theme, source: srcMode, width: 100, height: 24, dropDownHeight: 156 }); + $("#info_stage").jqxDropDownList({ theme: theme, source: srcStage, width: 150, height: 24, dropDownHeight: 125 }); var targetoptions = { inputMode: 'simple', spinMode: 'simple', theme: theme, width: 70, - height: 23, min:0, max: 40, decimalDigits: 1, spinButtons: true, @@ -140,6 +193,11 @@ $("#target_lo").jqxNumberInput( targetoptions ); $("#target_hi").jqxNumberInput( targetoptions ); + $("#Profile1").jqxButton({ template: "info", width: '150px', height: 24, theme: theme }); + $("#Profile2").jqxButton({ template: "info", width: '150px', height: 24, theme: theme }); + $("#Profile1").hide(); // Hide these until they are needed. + $("#Profile2").hide(); + function sendBase(stage, mode, tlo, thi) { console.log("sendBase("+stage+", "+mode+", "+tlo+", "+thi+")"); @@ -194,6 +252,23 @@ }); } + function sendProfile(payload) { + + console.log("sendProfile("+payload+")"); + var data = 'node='+record.node+'&alias='+record.alias+'&payload='+payload; + $.ajax({ + url: "cmd_fermenter.php", + data: data, + type: "POST", + success: function(data) { + //do something after something is received from php + }, + error: function(jqXHR, textStatus, errorThrown) { + console.log("sendBase() error"); + } + }); + } + var url = "getfermenter.php?uuid='" + my_uuid + "'"; var source = { datatype: "json", @@ -217,9 +292,12 @@ { name: 'cooler_usage', type: 'int' }, { name: 'fan_state', type: 'int' }, { name: 'fan_usage', type: 'int' }, + { name: 'light_address', type: 'string' }, { name: 'light_state', type: 'int' }, { name: 'light_usage', type: 'int' }, + { name: 'door_address', type: 'string' }, { name: 'door_state', type: 'int' }, + { name: 'psu_address', type: 'string' }, { name: 'psu_state', type: 'int' }, { name: 'mode', type: 'string' }, { name: 'alarm', type: 'int' }, @@ -228,7 +306,7 @@ { name: 'profile_uuid', type: 'string' }, { name: 'profile_name', type: 'string' }, { name: 'profile_state', type: 'string' }, - { name: 'profile_precent', type: 'int' }, + { name: 'profile_percent', type: 'int' }, { name: 'profile_inittemp_high', type: 'float' }, { name: 'profile_inittemp_low', type: 'float' }, { name: 'profile_steps', type: 'string' }, @@ -243,7 +321,8 @@ record = dataAdapter.records[0]; var oline = (record.online) ? "On-line" : "Off-line"; $("#info_uuid").html(record.uuid); - $("#info_system").html(record.node + "/" + record.alias + " " + oline); + $("#info_system").html(record.node + "/" + record.alias); + $("#info_online").html(oline); $("#info_beer").html(record.beercode + " - " + record.beername); $("#info_mode").jqxDropDownList('selectItem', record.mode); $("#info_stage").jqxDropDownList('selectItem', record.stage); @@ -264,12 +343,12 @@ $("#target_hi").jqxNumberInput({ readOnly: true, Width: 50, spinButtons: false }); } - if (record.online && (record.door_state != "0")) { + if (record.online && record.door_address && (record.door_state == "0")) { $("#fermenter_doorled").html('<div class="LEDyellow_on"></div>Door'); } else { $("#fermenter_doorled").html('<div class="LEDyellow_off"></div>Door'); } - if (record.online && (record.light_state != "0")) { + if (record.online && record.light_address && (record.light_state != "0")) { $("#fermenter_lightled").html('<div class="LEDyellow_on"></div>Light'); } else { $("#fermenter_lightled").html('<div class="LEDyellow_off"></div>Light'); @@ -279,8 +358,10 @@ $("#fermenter_powerled").html('<div class="LEDblue_on"></div>Power'); $("#select_beer").jqxDropDownList({ disabled: true }); $("#select_beer").jqxDropDownList('clearSelection'); + $("#select_beer").hide(); } else { $("#fermenter_powerled").html('<div class="LEDblue_off"></div>Power'); + $("#select_beer").show(); $("#select_beer").jqxDropDownList({ disabled: false }); } if (record.online && (record.alarm != "0")) { @@ -317,6 +398,51 @@ $("#fermenter_toggle3").val( (record.fan_state != "0") ); } + if (record.online && (record.mode == "PROFILE")) { + if (record.profile_state == "OFF") { + $("#select_profile").show(); + $("#select_profile").jqxDropDownList({ disabled: false }); + $("#info_mode").jqxDropDownList({ disabled: false }); + $('#Profile1').jqxButton({ template: "success", value: "Starten" }); + $("#Profile1").show(); + $("#Profile2").hide(); + $("#status_profile").html(''); + } else if (record.profile_state == "RUN") { + $("#select_profile").jqxDropDownList({ disabled: true }); + $("#select_profile").hide(); + $("#info_mode").jqxDropDownList({ disabled: true }); + $('#Profile1').jqxButton({ template: "danger", value: "Afbreken" }); + $('#Profile2').jqxButton({ template: "primary", value: "Pauze" }); + $("#Profile1").show(); + $("#Profile2").show(); + $("#status_profile").html('Profiel actief, '+record.profile_percent+'% gereed'); + } else if (record.profile_state == "PAUSE") { + $("#select_profile").jqxDropDownList({ disabled: true }); + $("#select_profile").hide(); + $("#info_mode").jqxDropDownList({ disabled: true }); + $('#Profile1').jqxButton({ template: "danger", value: "Afbreken" }); + $('#Profile2').jqxButton({ template: "success", value: "Doorgaan" }); + $("#Profile1").show(); + $("#Profile2").show(); + $("#status_profile").html('Profiel pauze, '+record.profile_percent+'% gereed'); + } else if (record.profile_state == "DONE") { + $("#select_profile").jqxDropDownList({ disabled: true }); + $("#select_profile").hide(); + $("#info_mode").jqxDropDownList({ disabled: true }); + $('#Profile1').jqxButton({ template: "primary", value: "Profiel Ok" }); + $("#Profile1").show(); + $("#Profile2").hide(); + $("#status_profile").html('Profiel is gereed'); + } + } else { + $("#select_profile").show(); + $("#select_profile").jqxDropDownList({ disabled: false }); + $("#info_mode").jqxDropDownList({ disabled: false }); + $("#Profile1").hide(); + $("#Profile2").hide(); + $("#status_profile").html(''); + } + $("#gaugeContainer_air").jqxGauge( { caption: { value: 'Air: '+record.air_temperature.toFixed(3) }}); $('#gaugeContainer_air').jqxGauge({ value: record.air_temperature }); if (record.online && (record.air_state == "OK")) { @@ -359,12 +485,23 @@ newProduct = false; skip = true; } + if (newProfile) { + sendProfile(ppayload); + newProfile = false; + skip = true; + } + if (skip) { + schedule = 4; // 2 seconds wait to get the results + } else { + if (schedule > 0) + schedule--; + } - if (! skip) { - // Only if we didn't send a command so that a command can be processed. + if (schedule <= 0) { dataAdapter.dataBind(); + schedule = 20; } - }, 10000); + }, 500); $('#info_mode').on('change', function (event) { record.mode = args.item.value; @@ -386,6 +523,29 @@ newProduct = true; } }); + $("#select_profile").on('select', function (event) { + if (event.args) { + var index = event.args.index; + var datarecord = profilelist.records[index]; + if (datarecord.record == -1) { + ppayload = '{"profile":null}'; + } else { + ppayload = '{"profile":{"uuid":"'+datarecord.uuid+'","name":"'+datarecord.name+'",'; + ppayload += '"inittemp":{"low":'+datarecord.inittemp_lo+',"high":'+datarecord.inittemp_hi+'},'; + ppayload += '"fridgemode":'+datarecord.fridgemode+',"steps":['; + for (var i = 0; i < datarecord.steps.length; i++) { + var row = datarecord.steps[i]; + if (i > 0) + ppayload += ','; + ppayload += '{"steptime":'+row['steptime']+',"resttime":'+row['resttime']; + ppayload += ',"target_lo":'+row['target_lo']+',"target_hi":'+row['target_hi']; + ppayload += ',"fridgemode":'+row['fridgemode']+',"name":"'+row['name']+'"}'; + } + ppayload += ']}}'; + } + newProfile = true; + } + }); $('#target_lo').on('change', function (event) { record.setpoint_low = parseFloat(event.args.value); @@ -446,10 +606,31 @@ newSwitch = true; } }); - + $("#Profile1").click(function () { + if (record.mode == "PROFILE") { + if (record.profile_state == "OFF") { + ppayload = '{"profile":{"command":"start"}}'; + newProfile = true; + } else if ((record.profile_state == "RUN") || (record.profile_state == "PAUSE")) { + ppayload = '{"profile":{"command":"abort"}}'; + newProfile = true; + } else if (record.profile_state == "DONE") { + ppayload = '{"profile":{"command":"done"}}'; + newProfile = true; + } + } + }); + $("#Profile2").click(function () { + if (record.mode == "PROFILE") { + if ((record.profile_state == "RUN") || (record.profile_state == "PAUSE")) { + ppayload = '{"profile":{"command":"pause"}}'; + newProfile = true; + } + } + }); // The chart button. - $("#FLog").jqxButton({ template: "info", width: '150px', theme: theme }); + $("#FLog").jqxButton({ template: "primary", width: '150px', theme: theme }); $("#FLog").click(function () { var url="log_fermentation.php?code=" + record.beercode + "&name=" + record.beername; window.open(url);
--- a/www/js/profile_fermentation.js Sat Jan 12 20:18:54 2019 +0100 +++ b/www/js/profile_fermentation.js Sat Jan 19 12:05:37 2019 +0100 @@ -62,7 +62,7 @@ { name: 'name', type: 'string' }, { name: 'inittemp_lo', type: 'float' }, { name: 'inittemp_hi', type: 'float' }, - { name: 'fridgemode', type: 'bool' }, + { name: 'fridgemode', type: 'int' }, { name: 'totalsteps', type: 'int' }, { name: 'duration', type: 'int' }, { name: 'steps', type: 'array' }
--- a/www/mon_fermenter.php Sat Jan 12 20:18:54 2019 +0100 +++ b/www/mon_fermenter.php Sat Jan 19 12:05:37 2019 +0100 @@ -9,13 +9,38 @@ <div id="fermenter_table"> <div id="fermenter_info"> <table style='width: 100%; padding: 10px;'> + <col width="20%"> + <col width="40%"> + <col width="40%"> <tr><th colspan=3>Klimaatkast overzicht</th></tr> - <tr><td>Uuid</td><td colspan="2"><div id="info_uuid"></div></td></tr> - <tr><td>Systeem</td><td colspan="2"><div id="info_system"></div></td></tr> - <tr><td>Code en bier</td><td><div id="info_beer"></div></td><td><div id="select_beer"></div></td></tr> - <tr><td>Werking</td><td colspan="2"><div id="info_mode"></div></td></tr> - <tr><td>Vergisting fase</td><td colspan="2"><div id="info_stage"></div></td></tr> - <tr><td>Vergisting profiel</td><td><div id="info_profile"></div></td><td><div id="select_profile"></div></td></tr> + <tr style="height: 25px;"> + <td>Uuid</td> + <td colspan="2"><div id="info_uuid"></div></td> + </tr> + <tr style="height: 25px;"> + <td>Systeem</td> + <td><div id="info_system"></div></td> + <td><div id="info_online"></div></td> + </tr> + <tr style="height: 25px;"> + <td>Code en bier</td> + <td><div id="info_beer"></div></td> + <td><div id="select_beer"></div></td> + </tr> + <tr style="height: 25px;"> + <td>Werking</td> + <td><div id="info_mode"></div></td> + <td><input type="button" id="Profile1" value="Profile 1" /><input style="margin-left: 10px;" type="button" id="Profile2" value="Profile 2" /></td> + </tr> + <tr style="height: 25px;"> + <td>Vergisting fase</td> + <td colspan="2"><div id="info_stage"></div></td> + </tr> + <tr style="height: 25px;"> + <td>Vergisting profiel</td> + <td><div id="info_profile"></div></td> + <td><div id="select_profile"></div><div id="status_profile"></div></td> + </tr> </table> </div> </div>