More FHIR on the pi…
June 21, 2016 4 Comments
So this is in the nature of the ‘I’m doing it this way just because I can!’
The background is that I want to create a series of time lapse pictures from a property overlooking a tidal river that doesn’t have internet access, and to be able to access those images remotely. (The property is in Waipu – rural New Zealand!)
I’m planning on using a raspberry Pi (with a camera) to take the photos, then upload them to a server from where I can generate the video sequence. (Because I have to use a cellular connection to access the net, I can’t host the images directly off the pi – which would have been my preferred option).
My original thought was to set up a simple hosted server and database (likely node.js and mongoDb) and have the pi regularly send the images there using HTTP, and then I thought – why not use FHIR? The server side then becomes easy as I can use an instance of a reference server (likely the HAPI CLI server) to receive and store the images. There was an added bonus that I could get to play with python a bit – and see how it handles sending FHIR resources.
Now, I’m the first to admit that this is hardly the intended use of FHIR – and that there are much better solutions you could use, but the opportunity to experiment with the pi as a FHIR client is certainly useful as I can imagine that as a real use case – imaging the pi acting as a home-based hub sending patient observations from devices to a FHIR server in the cloud.
As it turned out, it was really easy to do this – at least in a prototype fashion.
Here the code for the python script (and I’ll use cron to call it on a regular basis):
import json import base64 import requests import time from datetime import datetime import picamera from sense_hat import SenseHat sense = SenseHat() url = "http://fhir.hl7.org.nz/dstu2/Media" fileName = "images/pic"+str(time.time())+".jpg" # colours for the sense hat colour_red = [255, 0, 0] colour_white = [255, 255, 255] colour_blue = [0,0,255] colour_green = [0,128,0] colour_yellow = [255,255,0] # image dimensions image_height = 620 image_width = 480 sense.clear(colour_yellow) with picamera.PiCamera() as camera: camera.resolution = (image_height,image_width) camera.start_preview() # Camera warm-up time print('Waiting for camera') time.sleep(2) camera.stop_preview() camera.capture(fileName) sense.clear(colour_blue) #to indicate picture saved # load the file and send with open (fileName, "rb") as myfile: pic = myfile.read() # code for FHIR object reference = {} reference['reference'] = "Location/hayWaipu" extensions = [] extensionLocation = {} extensionTime = {} extensionLocation['url'] = "http://fhir.hl7.org.nz/StructureDefinition/locationOfMedia" extensionLocation['valueReference'] = reference extensions.append(extensionLocation) extensionTime['url'] = "http://fhir.hl7.org.nz/StructureDefinition/locationOfMedia" extensionTime['valueDateTime'] = datetime.now().strftime("%Y-%m-%dT%H:%m:%S") extensions.append(extensionTime) data = {} data['extension'] = extensions data['resourceType'] = 'Media' data['type'] = 'photo' data['deviceName'] = 'rpi' data['height'] = image_height data['width'] = image_width content = {} content['data'] = base64.b64encode(pic) content['contentType'] = 'image/jpg' data['content'] = content json_data = json.dumps(data) headers = {'content-type':'application/json+fhir'} print('Sending picture to ' + url) r = requests.post(url=url, data=json_data, headers=headers) if (r.status_code == 201): sense.clear(colour_green) print(r.headers['location']) print('Image saved') else: sense.clear(colour_red) print(r.json())
It’s actually longer than it needs to be as I decided to use the ‘sense hat’ as a visual indicator of where the script was in the overall process (I had it lying around – a simple LED might be better) – although the fact that it has a number of other sensors (temperature, humidity etc.) does suggest that I could collect other observations.
It starts by importing the various libraries it needs (I’m using the requests library to make the actual REST call) and then activates the camera, waits a couple of seconds and takes a photo – saving it to a file with a name constructed from the current time (that way I have a local copy of the images – though I’ll need some way to ensure they don’t fill up the pi!)
Next it constructs a Media resource to contain the actual image as a base64 encoded attachment.
I added a couple of extensions – one to record the date the image was taken, and the other so I could have it reference a Location resource (the closest existing match was ‘specimen’ which didn’t feel quite right…). I still have to create the extension definitions (StructureDefinition resources) but I will!
So this all works, though there are a few enhancements that come to mind:
- Better logging to assist troubleshooting is likely to be required when I deploy for real
- The use of the sense hat is a bit overkill – perhaps a multi colour LED that does the same thing and maybe a small LCD screen showing the last operation?
- Rather than storing the image as a base-64 encoded attachment (with associated overhead), I might store it as a binary resource referenced from the Media – or maybe an Observation might be better?
- I could add other observations (temperature, humidity & such like)
- I should really shift the resource creating stuff to a separate function – maybe a separate module, just to keep the main script tidier
Anyway, a fun little experiment exploring FHIR on the raspberry pi!
What a somewhat special way to use FHIR on. Way to go! I gave it a try to see if I could decode the base64 encoded pictures but no luck. Taking the content of the value of eg. http://fhir.hl7.org.nz/dstu2/Media/93349 and decode it gave something that could look like some binary data, it was not png content (ÿØÿácúExif MM *) {binary chars omitted}
Oops – that what comes of posting before the job is complete! I’ll see what is going wrong…
Shit happens when you publish it on the web … let me know when its working. I would love to see some pictures from ‘down under’ on a FHIR server – and hey – it would probably be the first of its kind (the FHIR media server hosted on the continent of Oceania).
so there were 2 issues:
First – I had the mime type as image/png – and it is actually image/jpg
Second – my python file read was not correct as it didn’t specify a binary file.
I’ve corrected the post, and the image at http://fhir.hl7.org.nz/dstu2/Media/93389 works for me (it’s a picture out of my office window at dusk!) – no guarantees that this image will remain (in fact I’ll certainly delete it in the not too distant future) – but all you need is a pi and camera to duplicate it, so I’m not too worried about that 🙂
thanks again for pointing this out!