Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move display code to project-tetra-display repo #1

Merged
merged 2 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM golang:latest
EXPOSE 8000
RUN apt update \
&& apt install -y libzmq5-dev \
python3-zmq \
supervisor \
python3-pip
RUN go get github.com/pebbe/zmq4 && go get github.com/gorilla/websocket

RUN mkdir -p /var/log/supervisor
RUN mkdir -p /src/zmq_proxy/static
RUN mkdir -p /src/zmq_proxy/TestData
WORKDIR /src/zmq_proxy
COPY main.go /src/zmq_proxy
COPY static /src/zmq_proxy/static
RUN go build

COPY requirements.txt /src/zmq_proxy
RUN pip3 install -r /src/zmq_proxy/requirements.txt
COPY *.py /src/zmq_proxy/
COPY TestData/20200609T2358Z_patrickData.txt /src/zmq_proxy/TestData
COPY services.conf /etc/supervisor/conf.d/services.conf
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"]
14 changes: 14 additions & 0 deletions Documentation/HowToRunAnApplicationAtLaunchOnAnRPi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
How to Run an Application at Launch on a Raspberry Pi
=====================================================

Running an application at launch is fairly simple. You simply use the `autostart` system to add to the boot procedure (there are other ways, but `autostart` guarantees that the X windowing system is loaded). To do this, you need to create a file `/home/pi/.config/autostart/TetraVentilatorSplitter.desktop` (or whatever name `*.desktop`), and add this bit of code to it:

```
[Desktop Entry]
Name=TetraVentilatorSplitter
Exec=# Whatever you run to execute the application
```

Then you can save that file and `sudo reboot` and the Pi will launch into the application specified.

This is based on the tutorial [here](https://learn.sparkfun.com/tutorials/how-to-run-a-raspberry-pi-program-on-startup/all).
31 changes: 31 additions & 0 deletions Documentation/HowToRunDockerFromPython.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
How to Run a Docker Container from a Python Script
==================================================

Docker is a very useful tool for when you want to run an application from a known environment. If you're developing a Docker container and testing the components within it outside the container, you may want to write a test program to validate your container. The obvious way to do this in Python is by calling shell commands with `os.system()`. But you can, in fact, use the Docker SDK to do this!

This snippet here
```python
import docker

client = docker.from_env()
image = client.images.build(
path=".", tag="example:latest")
container_name = "example_container"
client.containers.run("example:latest",
name=container_name,
detach=True,
auto_remove=True,
ports={"8000/tcp": 8000})

# Test that it's working

client.containers.get(container_name).kill()
```
is equivalent to this shell script.
```bash
docker build -t example:latest .
docker run --rm -dp 8000:8000 --name example_container example:latest
# Test that it's working
docker kill example_container
```
You can learn more about the Docker SDK at https://docker-py.readthedocs.io/en/stable/.
28 changes: 28 additions & 0 deletions Documentation/HowToSetUpAnRPiForHeadlessDevelopment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
How to set up a Raspberry Pi for headless developement
======================================================

Writing software for a Raspberry Pi is an interesting challenge because the outcome of the software often depends on the particular hardware configuration of the Pi, especially if you're writing software that uses sensors and other auxilliarly hardware. The easiest way to write software then is to connect a monitor and keyboard to the Pi and do development directly on the hardware. However, this is suboptimal because you can't necessarily use your favorite text editor, and Pis up through the 3B+ can only connect to one monitor. A better solution is to do headless development where you send files from your big computer to the Pi over a network communication protocol.

To make this happen, you're going to need to set up SSH on the Pi and SFTP communication on you big computer.

SSH
---

There are many online tutorials to set up SSH on the Pi. I think [this one]() is good. Also as a quality-of-life thing, you can add your Pi's IP address to `/etc/hosts` so you don't have to type out the whole IP every time.

After you've done all that, you'll need to get onto your Pi with a monitor and keyboard and enter `ssh [username]@[hostname]` into the the terminal. Then you can remove your monitor and keyboard from the Pi for good. Enter `ssh [username]@[hostname]` into your big computer's terminal and you'll be set.

SFTP
----

The details of how to set up SFTP will depend on your text editor. I'll show how to do this for Sublime Text.

1. First, make sure the package manager is set up. Open the command palette with Ctrl+Shift+P (Linux/Windows) or Cmd+Shift+P (Mac) and type `Install Package Control` and hit Enter
2. Again open the command palette and type `Package Control: Install Package` and hit Enter
3. In the text box that pops up after you hit Enter, type `SFTP` and select the first option that comes up (the description should say something like "Commercial SFTP/FTP plugin - upload, sync, browse, remote edit, diff and vcs integration")
4. Open the root directory for your project with Sublime such that you see the side bar with all the files in it. Right click on the root folder and from the Tooltip menu select `SFTP>Map to Remote...`
5. This will create a file `sftp-config.json` in your project's root directory that defines how the SFTP plugin will connect to your Pi. Make sure to add this file to your `.gitignore` because it'll contain sensitive information like a password.
6. Enter your Pi's IP address for the `"host"` field, your username on the Pi (by default `pi`) for the `"username"` field, and your password for the Pi for the `"password"` field (make sure you have a password on your Pi if you don't already).
7. By default, you need to manually tell the SFTP program which file to upload to the Pi when. But if you set `"upload_on_save"` to `true`, then it'll upload every time you save.

Once you've got SSH and SFTP set up, you can just write code, it'll update on the Pi automatically, and the you can test you code in the Pi's terminal on your big computer.
35 changes: 35 additions & 0 deletions Documentation/HowToTurnOn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
How to turn on the Tetra Ventilator Splitter
============================================

1. Ensure that the splitter is connected to a power supply

2. Ensure that the airlines connecting the splitter and ventilator are attached (detailed in a serperate document)

3. Flip the on-off switch to on

4. After a short boot-up sequence, a screen showing data for each of the patient airlines should appear, which looks like this

![Tubing data information screen](https://cdn.discordapp.com/attachments/718703783730741290/720436682851352697/VentilatorDisplay_1.jpeg)

- If this screen doesn't appear, ensure that the Tetra Ventilator Splitter software is installed

5. Verify that all the tubing connections are good

1. Plug in a patient tubing to port 1

2. Connect the patient tubing to a lung model or a balloon

3. Turn on the ventilator

4. The numbers on column 1 of the Tubing Data Information Screen should be changing

- If the numbers are not changing, make sure the stop valve for that port is open

5. Turn the knobs on the control valves for that port. The PIP and PEEP values should change with them

- If they aren't changing, ensure all the pneumatic connections are made and tight

6. Repeat substeps 1.-5. for ports 2, 3, and 4

6. Sterilize the patient tubing used for testing and begin treating patients

16 changes: 16 additions & 0 deletions Documentation/HowToUseSPL06_007.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
How to Use the SPL06-007 Pressure Sensor
========================================

The SPL06-007 is a calibrated pressure sensor often used for drone applications. This describes how to use the sensor via it's I2C interface, though it'd only really be a change in the first step to use a 3- or 4-wire SPI interface (and in hardware of course). Note that I connected the sensor to a Raspberry Pi via an I2C multiplexor (mux), so the second step isn't necessary if you don't have that.

- To initialize I2C, I use Adafruit's busio.I2C(board.SCL, board.SDA)
- For the mux select, I write a [0-4] integer to 0x70 (there's also a mux on 0x74, but I don't have anything connected to it right now, so it doesn't do anything.
- I then reset the sensor to clear any previous state by writing 0b1001 to 0x0C
- After that, I set the sensor into standby mode by writing 0 to 0x08
- Then in the case of the tests I'm having issues with, I set the sensor to measure pressure at 1Hz with 16 measurements per sample by writing 0 | 0b0100 to 0x06. Because there are more than 8 measurements per sample, I also set the sensor to bit shift the pressure by writing 0b0100 to 0x09.
- I do the same to get the temperature, but now it's 1Hz 1 sample, so 0 | 0 gets written to 0x07.
- Then I set the op mode to "command-pressure" by writing 0b0001 to 0x08 so I can read out what the current pressure is.
- After waiting a few milliseconds for the measurement to be ready, I read addresses 0x00, 0x01, and 0x02 to get the pressure measurement.
- Then the op mode is changed to "command-temperature" by writing 0b0010 to 0x08.
- Finally, I read the temperature measurement from 0x03, 0x04, and 0x05

Binary file added Documentation/TubingDataInformationScreen.odp
Binary file not shown.
Binary file added Documentation/TubingDataInformationScreen.pdf
Binary file not shown.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Ventilator Splitter Display
===========================

A system to take pressure and flow data from sensors on a ventilator splitter, calculate descriptive parameters based on these data like PEEP or Tidal Volume, and display them for medical professionals to monitor. This is for use against COVID-19.

To set it up for tests, run `./setup.sh` to build the virtual environment and then `source ./venv/bin/activate` to activate it. To do the tests, run `./runtests.sh`. This will first show the results of unit tests and then behaviour tests.

To run the display, first make sure Docker is installed, then run these commands.

```bash
docker build -t zmq_proxy:latest .
docker run --rm -p 8000:8000 zmq_proxy:latest
```

Then open http://localhost:8000 in a browser. With this, you'll see a webpage which every second writes some JSON in a bullet list, where each bullet ought to looks something like this (though it won't be printed as nicely).

```json
{ "0": { "Flow Rate": -0.12102553332090354,
"Inspiratory Pressure": 25.185687032203397,
"PEEP": 7.600443036648329,
"Peak Pressure": 29.143715376593427,
"Tidal Volume": 2982.643040302767},
"1": { "Flow Rate": -0.1853025137003232,
"Inspiratory Pressure": 27.589362195098154,
"PEEP": 9.0296093948397,
"Peak Pressure": 32.05751894822633,
"Tidal Volume": 123.60199756683565},
"2": { "Flow Rate": -0.23654912423232322,
"Inspiratory Pressure": 26.474812956451874,
"PEEP": 7.607352013212795,
"Peak Pressure": 27.6944434648811,
"Tidal Volume": 3712.3769706397325},
"3": { "Flow Rate": 0.13331473843016745,
"Inspiratory Pressure": 10.52283673388029,
"PEEP": 7.33283292927223,
"Peak Pressure": 23.519565988527702,
"Tidal Volume": 359.06476658825846}}
```
Empty file added Scripts/__init__.py
Empty file.
18 changes: 18 additions & 0 deletions Scripts/green.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import tkinter as tk

# A cheezy thing to make a green screen to superimpose images onto

root = None

def destroy(event=None):
global root
root.destroy()

if "__main__" == __name__:
root = tk.Tk()
root.title("Green")
frame = tk.Frame(root, cursor="none", bg="green")
frame.pack(fill=tk.BOTH, expand=1)
root.bind("<Escape>", destroy)
root.attributes("-fullscreen", True)
root.mainloop()
24 changes: 24 additions & 0 deletions Scripts/i2c_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import constants
from tca9548a import I2CMux
import sys
from pathlib import Path
sys.path.append(str(Path(".").absolute().parent))


pressure_sensor_mux = I2CMux(constants.PRESSURE_SENSOR_MUX_ADDRESS)

print(f"Initial scan:\t\t{pressure_sensor_mux.scan()}")

for i in range(8):
pressure_sensor_mux.select_channel(i)
print(f"{constants.PRESSURE_SENSOR_MUX_ADDRESS:#x} Mux Port {i}:"
f"\t{pressure_sensor_mux.scan()}")
pressure_sensor_mux.close()

flow_sensor_mux = I2CMux(constants.FLOW_SENSOR_MUX_ADDRESS)

for i in range(8):
flow_sensor_mux.select_channel(i)
print(f"{constants.FLOW_SENSOR_MUX_ADDRESS:#x} Mux Port {i}:"
f"\t{flow_sensor_mux.scan()}")
flow_sensor_mux.close()
32 changes: 32 additions & 0 deletions Scripts/poll_spl06_007.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import time

from spl06_007 import PressureSensor, Calibrator, Communicator


if "__main__" == __name__:
print("--Initialization")
comms = Communicator(dump_communication=True)
print("--Set Op Mode")
comms.set_op_mode(PressureSensor.OpMode.command)
print("--Set Pressure Sampling")
comms.set_pressure_sampling()
print("--Set Temperature Sampling")
comms.set_temperature_sampling()

calibrator = Calibrator(comms.calibration_coefficients,
comms.pressure_scale_factor,
comms.temperature_scale_factor)
running = True
with comms:
while running:
try:
print("--Get Pressure")
raw_pressure = comms.raw_pressure()
print("--Get Temperature")
raw_temperature = comms.raw_temperature()
pressure = calibrator.pressure(raw_pressure, raw_temperature)
temperature = calibrator.temperature(raw_temperature)
time.sleep(1.0)
except Exception as exception:
print(exception) # TODO: change this to logging
running = False
Loading