diff --git a/benchtop-fe/src/App.vue b/benchtop-fe/src/App.vue index 1c06106..8563fb6 100644 --- a/benchtop-fe/src/App.vue +++ b/benchtop-fe/src/App.vue @@ -1,9 +1,14 @@ diff --git a/benchtop-fe/src/parsers/Hardware.js b/benchtop-fe/src/parsers/Hardware.js new file mode 100644 index 0000000..d4ff4cd --- /dev/null +++ b/benchtop-fe/src/parsers/Hardware.js @@ -0,0 +1,71 @@ +parseInstrumentInfo = (text) => { + const instrumentInfo = {}; + const lines = text.split("\n").slice(2); + + for (const line of lines) { + if (line) { + const [key, value] = line.trim().split(/\s\s+/); + instrumentInfo[key.trim()] = value.trim(); + } + } + + return instrumentInfo; +} + +parsePorts = (text) => { + text += "\n\n"; // Ensure extra newline to match on + const pattern = /(Test Port \d)/g; + const matches = text.split(pattern).slice(1); + const portData = {}; + + for (let i = 0; i < matches.length; i += 2) { + const port = matches[i]; + const calibration = matches[i + 1]; + portData[port] = parseCalibrationData(calibration); + } + + return portData; +} + +const KEEP = { + "Mass Flow Trans": ["Instrument Flow", "Master Reading"], + "Pressure Transducer": ["Instrument Pressure", "Master Value"], +}; + +parseCalibrationData = (text) => { + const pattern = /(Mass Flow Trans|Pressure Transducer)\n([\s\S]+?)\n\n/g; + const matches = [...text.matchAll(pattern)]; + const calibrationData = {}; + + for (const match of matches) { + const blockTitle = match[1]; + const blockContent = match[2]; + const lines = blockContent.trim().split("\n"); + lines.shift(); // Remove "=======" line + const deviceName = lines.shift().trim().split(/\s+/).slice(-1)[0].trim(); + const deviceData = { name: deviceName }; + + for (const line of lines) { + const [key, value] = line.trim().split(/\s\s+/); + const keyTrimmed = key.trim(); + + for (const start of KEEP[blockTitle]) { + if (keyTrimmed.startsWith(start)) { + deviceData[keyTrimmed] = value.trim(); + } + } + } + + calibrationData[blockTitle] = deviceData; + } + + return calibrationData; +} + +export default parseHardwareCalibration = (content, accuracy) => { + const sections = content.split("|| Hardware Calibration Report ||"); + const instrumentInfo = parseInstrumentInfo(sections[0]); + const calibrationData = parsePorts(sections[1]); + + return { instrument: instrumentInfo, calibration: calibrationData }; +} \ No newline at end of file diff --git a/benchtop-fe/src/parsers/Transducer.js b/benchtop-fe/src/parsers/Transducer.js new file mode 100644 index 0000000..bd64467 --- /dev/null +++ b/benchtop-fe/src/parsers/Transducer.js @@ -0,0 +1,111 @@ +inRange = (index, value, masterValues) => { + return ( + masterValues[index]["Low Limit"] <= value && value <= masterValues[index]["High Limit"] + ); +} + +delta = (index, value, masterValues) => { + return Math.abs(masterValues[index]["Low Limit"] - value); +} + +export default parseTransducer = (content, accuracy) => { + accuracy = accuracy / 100.0; // Comes in as Percent + const transducerData = []; + + // Split the content into sections based on the blank line + const sections = content.trim().split("\n\n"); + + for (const section of sections) { + // Split each section into lines + const lines = section.trim().split("\n"); + const filteredLines = lines.filter( + (line) => !line.startsWith("==") && line !== "|| Transducer Verify Report ||" + ); + filteredLines.shift(); + + // Extract the Transducer number and Transducer type + const transducerLine = filteredLines.shift().trim(); + const [, transducerName, partNumber] = transducerLine.split(null, 2); + + // Get part number and values + let value = null; + let unit = null; + let transducerType = null; + if (partNumber !== "Custom") { + value = partNumber.split(" ").pop(); + partNumber = partNumber.split(" ")[1]; + const match = value.match(/([0-9]+)([A-Z]+)/i); + if (match) { + [, value, unit] = match; + value = parseInt(value); + } + if (unit === "SCCM") { + transducerType = "Flow"; + } + if (unit === "PSIA") { + transducerType = "Pressure"; + } + } + + // Create an object to store the data for each transducer + const transducerInfo = { + Accuracy: accuracy, + "Part Number": partNumber, + Value: value, + Unit: unit, + "Limit ABS": value * accuracy * 1000, + "Transducer Name": transducerName, + "Transducer Type": transducerType, + "Gauge Reading": [], + "Master Value": [], + "Verify Date": "", + "Verify Time": "", + }; + + // Extract other information for the transducer + for (const line of filteredLines) { + const [key, val] = line.trim().split(/\s\s+/); + if (key.includes("Verify Date")) { + transducerInfo["Verify Date"] = val; + } else if (key.includes("Verify Time")) { + transducerInfo["Verify Time"] = val; + } else { + // Toss anything else where it belongs + const [, cleanKey] = key.split(/\W\d/); + if ( + cleanKey in transducerInfo || + key.includes(`Instrument ${transducerType}`) + ) { + const value = parseInt(val.split(" ")[0]) * 1000; + // special case Master to get the limits + if (cleanKey.includes("Master")) { + const hi = value + transducerInfo["Limit ABS"]; + const lo = value - transducerInfo["Limit ABS"]; + transducerInfo[cleanKey].push({ + "Low Limit": lo, + "Master Value": value, + "High Limit": hi, + }); + } + // Turn both Instrument Pressure and Instrument Flow to Gauge Reading + else if (key.includes(`Instrument ${transducerType}`)) { + transducerInfo["Gauge Reading"].push(value); + } else { + transducerInfo[cleanKey].push(value); + } + } + } + } + + // Once we have the readings and master values, we can do the math + transducerInfo["Gauge Reading"] = transducerInfo["Gauge Reading"].map((v, idx) => ({ + Value: v, + "In Range": inRange(idx, v, transducerInfo["Master Value"]), + Delta: delta(idx, v, transducerInfo["Master Value"]), + })); + + transducerData.push(transducerInfo); + } + + return transducerData; +} \ No newline at end of file diff --git a/benchtop-fe/src/style.css b/benchtop-fe/src/style.css index fcca92e..ce2edb1 100644 --- a/benchtop-fe/src/style.css +++ b/benchtop-fe/src/style.css @@ -33,6 +33,9 @@ body { margin: 0.25rem; margin-bottom: 2%; border-radius: 3px; + /* purple + background-color: #b39ddb; + border: 1px solid #7e57c2; */ background-color: #a1cbfa; border: 1px solid #4290e2; box-shadow: 0 2px 2px rgba(0,90,250,0.05), diff --git a/benchtopdevices/sheets/parsers/transducer.py b/benchtopdevices/sheets/parsers/transducer.py index eeb5e65..7acc6e0 100644 --- a/benchtopdevices/sheets/parsers/transducer.py +++ b/benchtopdevices/sheets/parsers/transducer.py @@ -1,7 +1,5 @@ import re import json -from pprint import pprint - def in_range(index, value, master_values): return ( diff --git a/benchtopdevices/sheets/templates/sheets/upload.html b/benchtopdevices/sheets/templates/sheets/upload.html deleted file mode 100644 index dd6b159..0000000 --- a/benchtopdevices/sheets/templates/sheets/upload.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - -
-
- {% csrf_token %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Customer

Customer Name{{ form.customer_name }}
On Site Calibration{{ form.onsite_cal }}
Control Doc#{{ form.control_doc }}
Technician{{ form.technician }}

Instrument

Model:{{ form.instrument_model }}
Calibration Date:{{ form.instrument_calibration_date }}
Calibration Due Date:{{ form.instrument_calibration_due_date }}
Serial Number{{ form.serial_number }}
Channel{{ form.channel }}
Transducer Model:{{ form.transducer_model }}
Transducer Span:{{ form.transducer_span }}

Primary Calibration Device

Model{{ form.calibration_model }}
Serial #{{ form.calibration_serial }}
Cal Date{{ form.calibration_date }}
Cal Due Date{{ form.calibration_due_date }}
Cert ID{{ form.calibration_cert_id }}

Environment

Accuracy{{ form.accuracy }}
Barometric Pressure (mbar){{ form.barometric_pressure }}
Temperature (°F){{ form.temperature }}
Humidity{{ form.humidity }}

Report Uploads

Report Type{{ form.report_type }}
One File: {{ form.both }}
As Found: {{ form.as_found }}As Left:{{ form.as_left }}
 
-
-
- -{% verbatim %} - -{% endverbatim %} - - \ No newline at end of file diff --git a/benchtopdevices/sheets/views.py b/benchtopdevices/sheets/views.py index c764eba..b75cbaa 100644 --- a/benchtopdevices/sheets/views.py +++ b/benchtopdevices/sheets/views.py @@ -1,4 +1,4 @@ -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import render from django.core.exceptions import ValidationError @@ -30,4 +30,4 @@ def upload_file(request): return HttpResponseRedirect("/") else: form = SheetForm() - return render(request, "sheets/upload.html", {"form": form}) \ No newline at end of file + return HttpResponse("hi")