Making sure patients are in their beds at certain times is most often a matter of nurses doing periodical checks during shifts. In more critical cases this is further monitored by video surveillance. In yet fewer cases patients are monitored by bed pressure mats or systems using AI that can detect absence and falls. All these systems have some things in common: they are expensive, hard to relocalize and require wiring or other close proximity infrastructure, such as Bluetooth or Wi-Fi. This makes them impractical and costly to deploy at smaller health care institutions, such as nursing homes, or even for home care.
Beds in hospitals are key resources. Unfortunately they move around. They may be located in single-rooms, shared recovery wards, in corridors or any place in-between. This transient behavior has posed an impossible challenge for optimizing bed usage and providing a live inventory.
The solutionAn affordable device utilizing KEMET’s Pyroelectric Infrared Sensor with low power requirements could be attached to patient's beds. An efficient microcontroller sends sensor events via a low-power wireless network, Nb-IoT. The device is able to operate for extended durations on small batteries and mobile operators provide coverage anywhere you could possibly move a bed.
This project covers a lot of ground. Some topics are pretty specific and even region-dependent, while others are general and can be applied to many types of IoT-projects. So many topics are covered that it would be hard to go in-depth of them all. I try to provide references to the sources I used to learn this myself. You will also find a few of the topics covered in my previous project descriptions on Hackster and element14.
Hardware
- SS Pyroelectric Infrared Sensor Modules (SS–430L)
- Rocket Scream Mini Ultra 8 MHz (Arduino Compatible)
- U-Blox Sara N210 (EE-NBIOT-01 v1.1 breakout module from Telenor)
Architecture
- UDP
- MQTT
- Azure IoT Hub
- Azure Stream Analytics
- Serverless functions (Azure Functions 3)
- FHIR
- Google Cloud Healthcare API
Measurement
- Power consumption optimization (Otii Arc)
- Oscilliscope
Rapid prototyping
- 3D modelling
- FDM 3D printing
This project was made as a submission to the design contest regarding KEMET's pyroelectric infrared sensor. The datasheet gives a pretty good description of it's benefits and intended usage. The sensors I have used in the past to detect motion, passive infrared sensors (PIR), have several drawbacks:
- They are power hungry, not suitable for battery operation.
- They can't differentiate between humans or inanimate objects.
- They are rather protruding
KEMET’s Pyroelectric Infrared Sensors use the pyroelectric effect of ceramic by absorbing infrared rays emitted from the human body. This detects the natural infrared signature produced by humans.
Through this project I assess whether the SS-430L is appropriate for the criteria I have defined.
When at first connecting the sensor to a digital pin on the microcontroller there were a lot of pulses. I rigged the sensor in a stable position and tested a few different materials to dampen the readings. The cable used came suggested from the community, a JST-SH 1.0mm 5 Pin.
First of all, operation could not be simpler; the breakout board outputs two pulses when a body emitting a certain heat enters or leaves it's field of view. The pulses are described as HIGH for 0.2 seconds each. The pause between the pulses are not described and left a bit of uncertainty. Using an oscilloscope I was able to observe the behavior and measure the pauses. I am not entirely sure I have interpreted everything the sensor is trying to tell me, and unfortunately I have not found any in-depth analysis from the manufacturer.
What I am looking for is two 0.2s pulses, 0.42s apart. Anything else is ignored. I started out believing I would be able to keep track of a body being in front of the sensor or not. This turned out to be hard to accomplish and I kept losing track. I proceeded with the approach of monitoring activity instead. I believe this data can provide valuable metric describing when beds are being used.
The sensor requires at least 3.4 volts DC power supply. Most low-power circuits I have used work with 3.3v logic. Often they operate based on a regulator that is efficient when provided with 3.0v or even 1.5v. This is handy as there are many options for batteries with low self-discharge in this range. I could of course combine e.g. 3 1.5 volt, or 2 3.0 volt batteries, but this adds volume to a potentially small device. Not really an obsticle, just inconvenient. For this project I therefore decided to use a 3.6 volt Saft LS 14500 AA Li-SOCl2 battery. I bought two, one to set aside as a control.
The datasheet specifies a 30s warmup time to accommodate for voltage stabilization. During my experiments this seems a bit much, but for this application in a final product I think it would be practical to set an even longer initialization time to allow for placement and adjustment of the device and for operators to get out of the way.
Using the amazing Otii Arc I made a profile of the power consumption of the sensor. I hooked the sensor up with a 3.6v supply from the Otii Arc. I was surprised to see that the sensor had an average current consumption of 663uA when idle, i.e. no external trigger. While this is way better than any comparable sensor I have seen it made me worry about battery life. In previous projects I have resorted to switching sensors off, using a MOSFET, to preserve power. In this project this would severly compromise the operation. Also a 30s warmup time complicates matters.
Consumption was an average of 928uA during a pulse.
Here is some advice on designing solutions using the sensor.
Rocket Scream Mini Ultra 8 MHz microcontrollerOutside testing the sensor and creating a submission for a competition this project was in great deal an excuse to test something I have had on my mind for a long while: Would it be possible to operate a NB-IoT radio with a simple MCU on a minimalistic development board? How far could power consumption be optimized? I had a few Rocket Scream Mini Ultra 8 MHz microcontrollers in stock just for this purpose. With all the rage about Raspberry Pi's these days I find it satisfying to be able to accomplish the required features with just enough hardware, with the upshot of being able to achieve long battery life.
There isn't a lot to be said about the Mini Ultra - it features an ATmega328P-AU, an efficient voltage regulator and works just like any other Arduino-compatible board. It uses 1.7uA in deep sleep, which is pretty impressive. You can find the schematics here. With no USB interface you rely on a standard row of FTDI pins for flashing firmware and serial communication. The FTDI interface is based on 3 volt logic.
NB-IoTFrom Wikipedia:
Narrowband IoT is a Low Power Wide Area Network (LPWAN) radio technology standard developed by 3GPP to enable a wide range of cellular devices and services. NB-IoT focuses specifically on indoor coverage, low cost, long battery life, and high connection density. NB-IoT uses a subset of the LTE standard, but limits the bandwidth to a single narrow-band of 200kHz. It uses OFDM modulation for downlink communication and SC-FDMA for uplink communications.
In March 2019, the Global Mobile Suppliers Association announced that over 100 operators have deployed/launched either NB-IoT or LTE-M networks. This number had risen to 142 deployed/launched networks by September 2019.
I have been testing NB-IoT since September 2018. However this would be my first real low-power attempt, setting a benchmark for future projects. The main advantage of NB-IoT I recognize is coverage. On the other hand you have to administrate SIM cards and PIN's. In this case I also used the operator's cloud platform for routing messages. This was practical for the project, but I wonder how manageble this would be if I wanted to go international. I could always rely on pure UDP-transmission to a destination of choice, but my understanding is that the operator coverage is restricted to my country anyway. The modem I use has eSIM, meaning no physical SIM card to manage, and no PIN. It is unclear if this is the way my operator will be moving forward.
I use an older breakout module, the EE-NBIOT-01 v1.1, from the Norwegian mobile operator Telenor. It features a U-Blox SARA N210 modem. You can find tutorials and Arduino libraries here. The library defaults to a low-power profile, suitable when the device expects no unsolicited transmissions from the cloud. Following the suggestions I have bypassed the voltage regulator, as it is pretty power hungry.
I started out attempting to communicate using MQTT/TLS 1.2 over LTE-M. This works fine, albeit a bit cumbersome per device with the Arduino MKR NB 1500 and it's SARA-R410M.
This option would however not be available with my hardware. My route would be to send JSON formatted data in UDP packets over NB-IoT. This would not allow for return messages from the operator's MQTT broker(hosted in AWS), but for this application that wouldn't matter. Or so I initially thought..
CircuitTo communicate with the NB-IoT radio I use software serial on pin 10 and 11. Further, the radio is directly powered by the devboard's 3v3 supply and of course GND.
The sensor is directly powered from the battery. This is not ideal, but I allow it for a prototype as the battery has a pretty flat voltage drop until it runs dry. I would not recommend this approach for other types of batteries, though I don't think you would risk more in this case other than unreliable behavior.
I added a micro switch between the battery and VIN on the devboard.
All is assembled as a sandwich around a standard protoboard, using headers for easy disassembly. A nylon spacer nut was used to position the sensor.
I have made a LoRaWAN mail box sensor that so far has survived for over 2 years on the same 2xAA batteries in varied north-of-arctic-circle climate. I started out profiling power consumption by a combination of uCurrent and an oscilloscope with serial decoding. This was a frustrating experience, until I discovered Otii Arc by Swedish Qoitech. In short it is a computer interfaced power supply with voltage meters, ammeters and serial decoding. Carefully placed Serial.println let's you track exact current consumption down to nA. You can even measure subsystems to compare on the same timeline.
What the Otii Arc can't measure is the time I am saving doing measure vs. code/circuit change iterations!
To get a sense of what we can achieve, here is the Mini Ultra running a standard Blink example with nothing attached:
When the LED is off the whole circuit is consuming about 5mA current. That's 5.000uA. When my mail box sensor is sleeping, it consumes about 8uA. When it transmits it consumes about 8mA in a very short burst.
I probably did 20-30 iterations trying to optimize the code and circuit with respect to current consumption. Being able to visualize the sensor pulses on the same timeline as current consumption and debug statements was increadibly valuable and helped me sort out sleep behavior and interrupt handling. You may download a profile here that can be viewed with Qoitech's software.
One of the challenges I faced when starting out with an Arduino sample for the sensor was that pulseIn would not work if the MCU got woken from deep sleep by an interrupt from the sensor. My code therefore assumes that it is in the start of a pulse when it wakes and keeps track of time passed by itself. It then waits for a maximum period of time to see if a second pulse rises.
//Break after 2 close pulses
while (true)
{
PyroRead = 0; // Reset readings
IR_lastEdge = 0;
Serial.println(F("Sleeping, ready for input."));
Serial.flush();
powerDownInterrupt();
unsigned long PyroReadStart = micros();
while(digitalRead(PyroPin) == HIGH)
{
// Do nothing, wait for falling edge.
}
PyroRead = micros() - PyroReadStart;
IR_lastEdge = micros();
//Make sure trigger is over 198msec)
if (PyroRead > Sensor_PulseWidth)
{
Serial.print(F("PyroRead1: ")); Serial.println(PyroRead);
PyroRead = 0;
//Measure trigger point
PyroRead = pulseIn(PyroPin, HIGH); //, Sensor_PulseSpace + Sensor_PulseWidth/10);
if (PyroRead > Sensor_PulseWidth)
{
Serial.print(F("PyroRead2: ")); Serial.println(PyroRead);
break;
}
}
}
Another problem was that timing functions such as millis() don't work when sleeping. I could not rely on this to make the MCU sleep while the sensor warms up. This was solved by sleeping a fixed number of 4 second periods. I noticed that these sleep configurations in the LowPower library seem a bit unreliable, and that the 8 second configuration doesn't seem to work at all.
if(!Pyro_Initialized)
{
for (int i = 0; i<8; i++)
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
}
Pyro_Initialized = true;
}
For a production setting I would probably have removed the devboard LED altogether. For debugging I use it to indicate initialization as well as transmission. See the following measurement to compare current consumption with and without LED.
It is often necessary to use Serial.flush() before going to deep sleep, if not you might cut some of the characters.
I use the F() function to store string constants in flash memory to save space for code. I did not see significant differences in power consumption doing this.
In previous projects I have tried to measure if using Serial.println() will use noticeable amounts of power, without finding anything. Might as well leave those debug statements in.
The time a transmission takes is in the order of ms. Looking at the current consumption the radio keeps drawing some spikes. I believe the last spikes are caused by the radio listening for return transmissions.
The whole circuit settles with an average current consumption of 684uA when only the sensor is active. It will be interesting to see how long the device will be able to run in real life.
EnclosureThe enclosure I made serves the following purposes:
- Protect the circuit
- Allow mounting on beds
- Diffuse the sensor
I say "diffuse" even though this is a concept applicable to radiation in the visible spectrum. This sensor detects radiation in the infrared spectrum but I am not sure what term is appropriate. Maybe occlusion? Anyway, it is not a matter of using an opaque or transparent material, rather the material's ability to prevent infrared radiation through molecule composition, density and thickness.
I started the process by modelling the complete circuit in Fusion 360. This takes some time but has saved me countless iterations in the past. You only need to model the parts that define the edges or protrude from the main body.
Next I made a general profile around one of the sides and extruded a basic body. I made a lid for easy disassembly. This would be my first attempt at making a friction fit mechanism using tabs. I made some slots in case I had to use finger nails or a screwdriver to pry it open.
I had tested making a thin 3D printed plate to diffuse the sensor. The wall of the enclosure did however turn out to be too thick on the first iteration. Because of this I made a cut-out projected from the sensor to allow for experimentation without having to reprint the whole shell. In this process I decided to detach one of the walls to eliminate the need for printing support material, relying on glue instead. This sliced printing time in half (pun intended).
I used a GoPro mounting system with a clamp for the prototype. It's a bit overkill but let's me test what I need. I had to modify the hinges slightly to allow the desired assembly. Tamiya model saw to the rescue.
I attempted to 3D print some of the GoPro parts, but they didn't hold the tension.
I experimented with a whole lot of different options for the flow of data and architecture. Documenting them all would be a great effort and I have instead saved them for later projects.
- The sensor wakes the MCU.
- The MCU transmits a boolean to Horde, Telenor's IoT platform and MQTT broker.
- Horde publishes a message to my Azure IoT Hub (MQTT) broker.
- Azure Stream Analytics listens for input from IoT Hub.
- Stream Analytics queries incoming messages, transforms and calls serverless Azure Functions.
- Azure Function composes web requests and posts data to Google Healthcare API.
As it is operator specific I will not go into details on how to configure the operator's platform for my application. I followed this tutorial, as I have in the past. Basically I am registrering my devices for use with a MQTT broker. As this is a pretty common approach you might find applicable information in the tutorial even if you use a different operator.
In my application this platform is primarily used as a means for routing device messages to my own system. To accomplish this I needed to setup an output to my Azure IoT Hub. Azure IoT Hub is also basically a MQTT broker, but with certain idiosyncrasies. Specifically finding the correct way to authenticate a MQTT client to IoT Hub is far from obvious. I found my answers in the documentation and ended up with an output configured in this format:
Creating the password string involved creating a SAS-token with one of the available tools. I used the tool in Visual Studio. The documentation describes how to format both the username and password.
AzureYou can create a free Azure account to experiment with small amounts of resources.
Azure IoT HubIoT Hub is basically a MQTT broker with some helpful features for configuring devices and integrations. Learn how to set it up here. In my case any device that transmits via NB-IoT from my operator appears under one "device" in IoT Hub. This is the same name as used when setting up Horde to forward messages.
You could easily make IoT Hub forward any device message to for instance RequestBin with little configuration.
You could also make a custom Azure Functions that would trigger any time a message arrives.
You could do more sophisticated routing based on queries, like save telemetry to storage.
I knew more projects would appear in the near future bringing many types of devices with different forms of communication. Meta data and payloads would therefore differ vastly and I would want to be able to carefully pick destinations and transform data. For this Stream Analytics is quite powerful. Follow this quickstart to get it running.
Among the outputs I could route specific messages to custom serverless Azure Functions, written in c# in Visual Studio. This provides, in my opinion, the best IDE and tooling available. Debugging and deployment is just superior to anything comparable.
Before we get to the Azure Function we will look at inputs, outputs, data query and transformations. Stream Analytics provide a powerful SQL-like query language we can use to form data from different inputs and route to different outputs. Using the sampling tool you can record a stream of messages and test your queries. You can do this in Visual Studio or Visual Studio Code but old habits keep me in the Azure Console.
In Stream Analytics, under Inputs, add a new stream of type IoT Hub.
Follow this tutorial to create and deploy a shell of a Azure Function we can reference.
Under Outputs, add a new item of type Azure Function and select the function you created in the previous step.
Now we need to define a helper function for our message query to make sense of the payload from the device; Base64. It will convert ascii characters to binary representation. In Azure Console, Stream Analytics, under Functions, add a new Javascript UDF. Call it Base64, set output type to any. Find the source code here.
The next function parses hexadecimal values to integers; Hex2Int. Output type is bigint. Source code.
The query then looks like this (source code):
SELECT
msg.device.tags.name as DeviceName,
msg.device.deviceid as DeviceId,
DATEADD(MILLISECOND, msg.received % 1000, DATEADD(SECOND, msg.received / 1000, '1970-01-01T00:00:00Z')) as Received,
udf.Hex2Int(udf.Base64(msg.payload)) as PayloadInt
INTO
[IotaPublisherFunctionApp]
FROM
[eHealthIoTHubInput] msg
WHERE
msg.device.collectionId LIKE '17dh0cf43jg046'
My Azure Function extracts what I need from the payload and posts a resource update (bed occupied yes/no) to Google Healthcare API (source code).
I usually start by using the provided Azure Functions template to look at the data transmitted:
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
Live debugging will provide the JSON-formatted payload from Stream Analytics. Copy&paste this into a tool such as QuickType to generate a statically typed class.
Or play fast and loose and use dynamics.
As much as I would have loved to interface the sensor telemetry with the hospital system I develop professionally, there are a few implications. Firstly there might be legal implications of sharing this on a personal project and secondly it would not be available to anyone wanting to recreate it.
Enter Google Cloud Healthcare API. This is a great placeholder for any modern healthcare system that cares about interoperability. If a startup aims to support interoperability with Google Healthcare API, it will be pretty well positioned for future integrations with existing healthcare systems. Using FHIR as data description may avoid falling into the pit of having to support a myriad of custom integrations.
In short Healthcare API provides REST-endpoints, storage and pubsub infrastructure so you don't have to reinvent the wheel. In my application all I needed was to define locations and some beds. Then I could toggle occupancy status of these beds from the device messages.
I used the web based GUI (Cloud Console) to create my own Healthcare API instance, projects, datasets and FHIR data stores. I used both the gcloud CLI (both local and web) and Windows PowerShell to populate resources. I think the documentation is really good and it is mostly a matter of reading up on all of the topics and architecture.
I have shared Powershell scripts that create some beds in a FHIR store, as well as query them.
$cred = gcloud auth print-access-token
$headers = @{ Authorization = "Bearer $cred" }
$PROJECT_ID = ""
$LOCATION = ""
$DATASET_ID = "IoTHealthcareDataset"
$FHIR_STORE_ID = "ResourcesDataStore"
Invoke-RestMethod `
-Method Get `
-Headers $headers `
-Uri "https://healthcare.googleapis.com/v1beta1/projects/$PROJECT_ID/locations/$LOCATION/datasets/$DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Location/" | ConvertTo-Json
FHIRFHIR (Fast Healthcare Interoperability Resources) is the emerging standard for healthcare data interoperability. Using REST semantics, FHIR specifies a robust, extensible data model for interacting with clinical resources.
I use only the part of FHIR that concerns resources, locations and beds, in a healthcare institution.
ConclusionThe sensor behaved a bit different than I had expected, so I had to modify my approach a bit. Keeping state if a body is in front of the sensor or has left seems hard to maintain, I think baseing assumptions if a bed is in use on recent activity is a more reliable solution.
The NB-IoT aspect of the project worked really well and I was positively surprised at the sleep power consumption of the radio.
Google Healthcare is a nice stand-in for a real healthcare system.
The Rocket Scream devboard exceeded expectations and worked flawlessly for this application.
Final wordsI wish to thank KEMET and Hackster for presenting this design competition, it has taught me a lot in many different topics and I plan to use the sensor in future projects.
Comments