# HG changeset patch # User Michiel Broek # Date 1547895937 -3600 # Node ID 6470e5c6a0012ccf73995970b5f43c1d6a75283a # Parent 0ef62ec2d5b09044e0b35dcc69e0a01e82846b32 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. diff -r 0ef62ec2d5b0 -r 6470e5c6a001 .hgignore --- 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 diff -r 0ef62ec2d5b0 -r 6470e5c6a001 bmsd/fermenters.c --- 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 * - * 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); diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/Makefile --- 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 diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/cmd_fermenter.php --- 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 . '}\''; diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/css/style.css --- 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; diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/includes/db_profile_fermentation.php --- 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; } diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/js/mon_fermenter.js --- 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('
Door'); } else { $("#fermenter_doorled").html('
Door'); } - if (record.online && (record.light_state != "0")) { + if (record.online && record.light_address && (record.light_state != "0")) { $("#fermenter_lightled").html('
Light'); } else { $("#fermenter_lightled").html('
Light'); @@ -279,8 +358,10 @@ $("#fermenter_powerled").html('
Power'); $("#select_beer").jqxDropDownList({ disabled: true }); $("#select_beer").jqxDropDownList('clearSelection'); + $("#select_beer").hide(); } else { $("#fermenter_powerled").html('
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); diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/js/profile_fermentation.js --- 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' } diff -r 0ef62ec2d5b0 -r 6470e5c6a001 www/mon_fermenter.php --- 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 @@
+ + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Klimaatkast overzicht
Uuid
Systeem
Code en bier
Werking
Vergisting fase
Vergisting profiel
Uuid
Systeem
Code en bier
Werking
Vergisting fase
Vergisting profiel