Skip to content
Snippets Groups Projects
Commit 94bdf11a authored by Stephen Farry's avatar Stephen Farry
Browse files

merged changes

parents 47156f7d e5721e92
Branches
No related merge requests found
......@@ -6,7 +6,8 @@
- Boot as default and set your preferred options for country, password, etc.
> From command line on your local PC (not the pi):
- copy your ssh keys if you don't want a password every time
- generate and copy your ssh keys if you don't want a password every time
- ssh-keygen
- ssh-copy-id pi@MY-RPI-IPADDRESS
- then setup ansible:
- install ansible on your local PC with your package manager
......@@ -18,7 +19,7 @@ cd hev-sw/ansible
source hev-ansible.sh
cd playbooks
```
- add the address of your Raspberry Pi to the `hosts` file under the section `[hevpi]`
- add the address of your Raspberry Pi to the `hosts` file under the section `[hevpi]`. The default host file is found at /etc/ansible/hosts
- example :
```
[hevpi]
......
......@@ -8,6 +8,8 @@ var initial_yaxis_pressure = [];
var initial_yaxis_volume = [];
var initial_yaxis_flow = [];
var fio_reading;
/**
* Request data from the server, add it to the graph and set a timeout
* to request again
......@@ -31,9 +33,8 @@ function init_results(){
url: '/last_N_data',
success: function(data) {
for (i=0; i<data.length; i++) {
var seconds = data[i]["timestamp"];
var seconds = data[i]["timestamp"]/1000;
if ( seconds == "" ) continue;
console.log(seconds);
initial_yaxis_pressure.push({x : seconds, y : data[i]["pressure_buffer"]});
initial_yaxis_volume.push({x : seconds, y : data[i]["pressure_inhale"]});
initial_yaxis_flow.push({x : seconds, y : data[i]["temperature_buffer"]});
......@@ -49,7 +50,7 @@ function init_results(){
initial_yaxis_pressure[i][0] = initial_yaxis_pressure[i][0] - current_timestamp;
initial_yaxis_volume[i][0] = initial_yaxis_volume[i][0] - current_timestamp;
initial_yaxis_flow[i][0] = initial_yaxis_flow[i][0] - current_timestamp;
}
}
},
cache: false
......@@ -94,7 +95,11 @@ function requestChartVar() {
$.ajax({
url: '/live-data',
success: function(point) {
var seconds = point["timestamp"];
fio_reading = (point["pressure_buffer"]).toFixed(0) ;
//console.log(fio_reading);
fio_gauge.data.datasets[0].gaugeData['value'] = fio_reading;
var seconds = point["timestamp"]/1000;
// get difference between last time stamp and this and apply to existing points
var diff = 0;
if ( current_timestamp == -1 ){
......@@ -129,6 +134,8 @@ function requestChartVar() {
chart_pressure.update();
chart_flow.update();
chart_volume.update();
fio_gauge.update();
},
cache: false
});
......@@ -353,4 +360,22 @@ $(document).ready(function() {
});
var ctx = document.getElementById("example_gauge").getContext("2d");
fio_gauge = new Chart(ctx, {
type: "tsgauge",
data: {
datasets: [{
backgroundColor: ["#0fdc63", "#fd9704", "#ff7143"],
borderWidth: 0,
gaugeData: {
value: 0,
valueColor: "#ff7143"
},
gaugeLimits: [0, 50, 100]
}]
},
options: {
events: []
}
});
......@@ -13,34 +13,48 @@ function requestChartVar() {
success: function(point) {
if( chart_PV.data.datasets[1].data.length > 100 ){
chart_PV.data.datasets[1].data.shift();
chart_FV.data.datasets[1].data.shift();
chart_VF.data.datasets[1].data.shift();
chart_PF.data.datasets[1].data.shift();
}
// point labelled as: (stealing definitions from Chart-display.js)
// Pressure = pressure_buffer
// Flow = pressure_inhale ??
// Volume = temperature_buffer !!?
chart_PV.data.datasets[1].data.push({x: point["temperature_buffer"],
y: point["pressure_buffer"]});
chart_FV.data.datasets[1].data.push({x: point["temperature_buffer"],
y: point["pressure_inhale"]});
chart_PF.data.datasets[1].data.push({x: point["pressure_inhale"],
y: point["pressure_buffer"]});
chart_PV.data.datasets[0].data =
[{x: point["temperature_buffer"],y: point["pressure_buffer"]}];
var pressure = point["pressure_buffer"];
var volume = point["temperature_buffer"];
var flow = point["pressure_inhale"];
chart_FV.data.datasets[0].data =
[{x: point["temperature_buffer"], y: point["pressure_inhale"]}];
// to quote the AAMI:
//For Pressure-Volume loops, the graph
//is required to use delivered volume on the vertical axis
//and airway pressure on the horizontal axis. Positive
//values should increase in up/right directions. Every
//breath resets the graph, setting the volume back at the
//origin.
chart_PF.data.datasets[0].data =
[{x: point["pressure_inhale"], y: point["pressure_buffer"]}];
//For Flow-Volume loops the graph is required to use flow
//rate on the vertical axis and delivered volume on the
//horizontal axis. Positive values should increase in the
//up/right directions. Every breath resets the graph,
//setting the volume back at the origin. The document also
//suggests that there could be another version using
//exhalation flow, if possible.
// loops:
chart_PV.data.datasets[1].data.push({x: pressure, y: volume});
chart_VF.data.datasets[1].data.push({x: volume, y: flow});
chart_PF.data.datasets[1].data.push({x: pressure, y: flow});
// current data:
chart_PV.data.datasets[0].data = [{x: pressure, y: volume}];
chart_VF.data.datasets[0].data = [{x: volume, y: flow}];
chart_PF.data.datasets[0].data = [{x: pressure, y: flow}];
// now run chart updates
chart_PV.update();
chart_FV.update();
chart_VF.update();
chart_PF.update();
console.info("chart_PV.data", chart_PV.data);
},
},
cache: false
});
setTimeout(requestChartVar, 200);
......@@ -53,55 +67,43 @@ $(document).ready(function() {
chart_PV = new Chart(ctx_PV, {
type: 'scatter',
data: {datasets: [{data: [],
label: "Pressure:Volme (current)",
label: "Pressure (x) [mbar]: Volume (y) [ml] (current)",
borderColor: "rgb(128,0,0)",
pointBackgroundColor : "rgb(128,0,0)",
fill: true},
{data: [],
label: "Loop Pressure:Volme (last 20s)",
label: "Loop (20s)",
borderColor: "rgb(51,99,255)",
pointBackgroundColor : "rgb(51,99,255)",
fill: false },
]},
options: {elements: { point: { radius: 5}},
scales: {xAxes: [{type: 'linear',
position: 'bottom',
lablelString: 'temperature_buffer??',
display: true,
ticks: {min: -1000, max: 1500,
stepSize: 500, fontSize:25 }}],
yAxes: [{type: 'linear',
position: 'left',
lablelString: 'pressure_buffer??',
display: true,
scales: {xAxes: [{display: true,
ticks: {min: 0, max: 25,
stepSize: 5, fontSize: 25 }}]}}
stepSize: 5, fontSize: 25 }}],
yAxes: [{display: true,
ticks: {min: -1000, max: 1500,
stepSize: 500, fontSize:25 }}]}}
});
var ctx_FV = document.getElementById('flow_volume_chart');
chart_FV = new Chart(ctx_FV, {
var ctx_VF = document.getElementById('flow_volume_chart');
chart_VF = new Chart(ctx_VF, {
type: 'scatter',
data: {datasets: [{data: [],
label: "Flow:Volme (current)",
label: "Volume (x) [ml]: Flow (y) [ml/min] (current)",
borderColor: "rgb(128,0,0)",
pointBackgroundColor : "rgb(128,0,0)",
fill: true },
{data: [],
label: "Loop Flow:Volme (last 20s)",
label: "Loop (20s)",
borderColor: "rgb(51,99,255)",
pointBackgroundColor : "rgb(51,99,255)",
fill: false }]}
,options: {elements: { point: { radius: 5}},
scales: {xAxes: [{type: 'linear',
position: 'bottom',
lablelString: 'temperature_buffer??',
display: true,
ticks: {min: -1000, max: 1500,
stepSize: 500, fontSize: 25 }}],
yAxes: [{type: 'linear',
position: 'left',
lablelString: 'pressure_inhale??',
display: true,
scales: {xAxes: [{display: true,
ticks: {min: -1000, max: 1500,
stepSize: 500, fontSize: 25 }}],
yAxes: [{display: true,
ticks: {min: 0, max: 300,
stepSize: 100, fontSize: 25 }}]}}
});
......@@ -110,28 +112,22 @@ $(document).ready(function() {
chart_PF = new Chart(ctx_PF, {
type: 'scatter',
data: {datasets: [{data: [],
label: "Pressure:Flow (current)",
label: "Pressure (x) [mbar]: Flow (y) [ml/min] (current)",
borderColor: "rgb(128,0,0)",
pointBackgroundColor : "rgb(128,0,0)",
fill: true },
{data: [],
label: "Loop Pressure:Flow (last 20s)",
label: "Loop (20s)",
borderColor: "rgb(51,99,255)",
pointBackgroundColor : "rgb(51,99,255)",
fill: false }]}
,options: {elements: { point: { radius: 5, fill: true}},
scales: {xAxes: [{type: 'linear',
position: 'bottom',
lablelString: 'pressure_inhale??',
display: true,
scales: {xAxes: [{display: true,
ticks: {min: 0, max: 25 ,
stepSize: 5 , fontSize: 25 }}],
yAxes: [{display: true,
ticks: {min: 0, max: 300,
stepSize: 100, fontSize: 25 }}],
yAxes: [{type: 'linear',
position: 'left',
lablelString: 'pressure_buffer??',
display: true,
ticks: {min: 0, max: 25,
stepSize: 5, fontSize: 25 }}]}}
stepSize: 100, fontSize: 25 }}]}}
});
});
......
(function () {
if (!window.Chart) {
return;
}
function GaugeChartHelper() {
}
GaugeChartHelper.prototype.setup = function(chart, config) {
this.chart = chart;
this.ctx = chart.ctx;
this.limits = config.data.datasets[0].gaugeLimits;
this.data = config.data.datasets[0].gaugeData;
var options = chart.options;
this.fontSize = options.defaultFontSize;
this.fontStyle = options.defaultFontFamily;
this.fontColor = options.defaultFontColor;
this.ctx.textBaseline = "alphabetic";
this.arrowAngle = 25 * Math.PI / 180;
this.arrowColor = config.options.indicatorColor || options.arrowColor;
this.showMarkers = typeof(config.options.showMarkers) === 'undefined' ? true : config.options.showMarkers;
if (config.options.markerFormatFn) {
this.markerFormatFn = config.options.markerFormatFn;
} else {
this.markerFormatFn = function(value) {
return value;
}
}
};
GaugeChartHelper.prototype.applyGaugeConfig = function(chartConfig) {
this.calcLimits();
chartConfig.data.datasets[0].data = this.doughnutData;
var ctx = this.ctx;
var labelsWidth = this.limits.map(function(label){
var text = this.markerFormatFn(label);
return ctx.measureText(text).width;
}.bind(this));
var padding = Math.max.apply(this, labelsWidth) + this.chart.width / 35;
var heightRatio = this.chart.height / 50;
chartConfig.options.layout.padding = {
top: this.fontSize + heightRatio,
left: padding,
right: padding,
bottom: heightRatio * 2
};
};
GaugeChartHelper.prototype.calcLimits = function() {
var limits = this.limits;
var data = [];
var total = 0;
for (var i = 1, ln = limits.length; i < ln; i++) {
var dataValue = Math.abs(limits[i] - limits[i - 1]);
total += dataValue;
data.push(dataValue);
}
this.doughnutData = data;
var minValue = limits[0];
var maxValue = limits[limits.length - 1];
this.isRevers = minValue > maxValue;
this.minValue = this.isRevers ? maxValue : minValue;
this.totalValue = total;
};
GaugeChartHelper.prototype.updateGaugeDimensions = function() {
var chartArea = this.chart.chartArea;
this.gaugeRadius = this.chart.innerRadius;
this.gaugeCenterX = (chartArea.left + chartArea.right) / 2;
this.gaugeCenterY = (chartArea.top + chartArea.bottom + this.chart.outerRadius) / 2;
this.arrowLength = this.chart.radiusLength * 2;
};
GaugeChartHelper.prototype.getCoordOnCircle = function(r, alpha) {
return {
x: r * Math.cos(alpha),
y: r * Math.sin(alpha)
};
};
GaugeChartHelper.prototype.getAngleOfValue = function(value) {
var result = 0;
var gaugeValue = value - this.minValue;
if (gaugeValue <= 0) {
result = 0;
} else if (gaugeValue >= this.totalValue) {
result = Math.PI;
} else {
result = Math.PI * gaugeValue / this.totalValue;
}
if (this.isRevers) {
return Math.PI - result;
} else {
return result;
}
};
GaugeChartHelper.prototype.renderLimitLabel = function(value) {
var ctx = this.ctx;
var angle = this.getAngleOfValue(value);
var coord = this.getCoordOnCircle(this.chart.outerRadius + (this.chart.radiusLength / 2), angle);
var align;
var diff = angle - (Math.PI / 2);
if (diff > 0) {
align = "left";
} else if (diff < 0) {
align = "right";
} else {
align = "center";
}
ctx.textAlign = align;
ctx.font = this.fontSize + "px " + this.fontStyle;
ctx.fillStyle = this.fontColor;
var text = this.markerFormatFn(value);
ctx.fillText(text, this.gaugeCenterX - coord.x, this.gaugeCenterY - coord.y);
};
GaugeChartHelper.prototype.renderLimits = function() {
for (var i = 0, ln = this.limits.length; i < ln; i++) {
this.renderLimitLabel(this.limits[i]);
}
};
GaugeChartHelper.prototype.renderValueLabel = function() {
var label = this.data.value.toString();
var ctx = this.ctx;
ctx.font = "30px " + this.fontStyle;
var stringWidth = ctx.measureText(label).width;
var elementWidth = 0.75 * this.gaugeRadius * 2;
var widthRatio = elementWidth / stringWidth;
var newFontSize = Math.floor(30 * widthRatio);
var fontSizeToUse = Math.min(newFontSize, this.gaugeRadius);
ctx.textAlign = "center";
ctx.font = fontSizeToUse + "px " + this.fontStyle;
ctx.fillStyle = this.data.valueColor || this.fontColor;
ctx.fillText(label, this.gaugeCenterX, this.gaugeCenterY);
};
GaugeChartHelper.prototype.renderValueArrow = function(value) {
var angle = this.getAngleOfValue(typeof value === "number" ? value : this.data.value);
this.ctx.globalCompositeOperation = "source-over";
this.renderArrow(this.gaugeRadius, angle, this.arrowLength, this.arrowAngle, this.arrowColor);
};
GaugeChartHelper.prototype.renderSmallValueArrow = function(value) {
var angle = this.getAngleOfValue(value);
this.ctx.globalCompositeOperation = "source-over";
this.renderArrow(this.gaugeRadius - 1, angle, this.arrowLength - 1, this.arrowAngle, this.arrowColor);
};
GaugeChartHelper.prototype.clearValueArrow = function(value) {
var angle = this.getAngleOfValue(value);
this.ctx.lineWidth = 2;
this.ctx.globalCompositeOperation = "destination-out";
this.renderArrow(this.gaugeRadius - 1, angle, this.arrowLength + 1, this.arrowAngle, "#FFFFFF");
this.ctx.stroke();
};
GaugeChartHelper.prototype.renderArrow = function(radius, angle, arrowLength, arrowAngle, arrowColor) {
var coord = this.getCoordOnCircle(radius, angle);
var arrowPoint = {
x: this.gaugeCenterX - coord.x,
y: this.gaugeCenterY - coord.y
};
var ctx = this.ctx;
ctx.fillStyle = arrowColor;
ctx.beginPath();
ctx.moveTo(arrowPoint.x, arrowPoint.y);
coord = this.getCoordOnCircle(arrowLength, angle + arrowAngle);
ctx.lineTo(arrowPoint.x + coord.x, arrowPoint.y + coord.y);
coord = this.getCoordOnCircle(arrowLength, angle - arrowAngle);
ctx.lineTo(arrowPoint.x + coord.x, arrowPoint.y + coord.y);
ctx.closePath();
ctx.fill();
};
GaugeChartHelper.prototype.animateArrow = function() {
var stepCount = 30;
var animateTimeout = 300;
var gaugeValue = this.data.value - this.minValue;
var step = gaugeValue / stepCount;
var i = 0;
var currentValue = this.minValue;
var interval = setInterval(function() {
i++;
this.clearValueArrow(currentValue);
if (i > stepCount) {
clearInterval(interval);
this.renderValueArrow();
} else {
currentValue += step;
this.renderSmallValueArrow(currentValue);
}
}.bind(this), animateTimeout / stepCount);
};
Chart.defaults.tsgauge = {
animation: {
animateRotate: true,
animateScale: false
},
cutoutPercentage: 95,
rotation: Math.PI,
circumference: Math.PI,
legend: {
display: false
},
scales: {},
arrowColor: "#444"
};
Chart.controllers.tsgauge = Chart.controllers.doughnut.extend({
initialize: function(chart) {
var gaugeHelper = this.gaugeHelper = new GaugeChartHelper();
gaugeHelper.setup(chart, chart.config);
gaugeHelper.applyGaugeConfig(chart.config);
chart.config.options.animation.onComplete = function(chartElement) {
gaugeHelper.updateGaugeDimensions();
gaugeHelper.animateArrow();
};
Chart.controllers.doughnut.prototype.initialize.apply(this, arguments);
},
draw: function() {
Chart.controllers.doughnut.prototype.draw.apply(this, arguments);
var gaugeHelper = this.gaugeHelper;
gaugeHelper.updateGaugeDimensions();
gaugeHelper.renderValueLabel();
if (gaugeHelper.showMarkers) {
gaugeHelper.renderLimits();
}
gaugeHelper.renderSmallValueArrow(gaugeHelper.minValue);
}
});
})();
......@@ -119,7 +119,8 @@
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/Chart.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/moment.js') }}"></script>
<script src="{{ url_for('static', filename='js/Chart.js') }}"></script>
<script src="{{ url_for('static', filename='js/Chart.js') }}"></script>
<script src="{{ url_for('static', filename='js/Gauge.js') }}"></script>
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/dataTables.bootstrap4.min.js') }}"></script>
......
......@@ -29,9 +29,10 @@
<div class = "row">
<div class = "range-button-container ml-auto mr-auto">
<input type="button" class="sb-nav-button" name="fivesecs" value="5s" onclick="setChartXaxisRange(-5,0)">
<input type="button" class="sb-nav-button" name="thirtysecs" value="30s" onclick="setChartXaxisRange(-30,0)">
<input type="button" class="sb-nav-button" name="thirtysecs" value="60s" onclick="setChartXaxisRange(-60,0)">
<input type="button" class="sb-nav-button" name="thirtysecs" value="90s" onclick="setChartXaxisRange(-90,0)">
<input type="button" class="sb-nav-button" name="sixtysecs" value="60s" onclick="setChartXaxisRange(-60,0)">
<input type="button" class="sb-nav-button" name="ninetysecs" value="90s" onclick="setChartXaxisRange(-90,0)">
</div>
</div>
</div>
......@@ -60,16 +61,15 @@
<div class="card-header d-flex align-items-center justify-content-between py-1 min-height-1b">
<a class="small text-dark col-center" href="#">FIO<sub>2</sub></a>
</div>
<div class="card-body px-1 py-1 tiny ml-auto mr-auto br-red">
<div class = "reading-wrapper br-red"><input class = "input-reading py-0" id = "fio2" value="62" type="number" readOnly disabled>%</div>
</div>
<!-- <div class="card-body px-1 py-1 tiny ml-auto mr-auto"><input class = "input-reading py-0" id = "fio2" value="62" type="number" readOnly disabled>%</div> -->
<div class = "main-chart-container"><canvas id="example_gauge"></canvas></div>
</div>
<div class="card-reading">
<div class="card-header d-flex align-items-center justify-content-between py-1 min-height-1b">
<a class="small text-dark col-center" href="#">P<sub>Peak</sub></a>
</div>
<div class="card-body px-1 py-1 tiny ml-auto mr-auto"><input class = "input-reading" id="p_peak" readOnly disabled value=20.0>cmH2O</div>
<div class="card-body px-1 py-1 tiny ml-auto mr-auto"><input class = "input-reading" id="p_peak" readOnly disabled value=20.0>cmH2O</div>
</div>
<!--- end row 1 -->
......
......@@ -39,7 +39,7 @@ class hevfromtxt():
# directly setting private member variables in this edge case
payload = CommsCommon.DataFormat()
payload._version = payload._RPI_VERSION
payload._timestamp = time_offset + self._timestamp[self._pos]
payload._timestamp = time_offset + self._timestamp[self._pos] * 1000 # timestamp in ms
payload._pressure_buffer = self._pressure[self._pos]
payload._pressure_inhale = self._volume[self._pos]
payload._temperature_buffer = self._flow[self._pos]
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment