adammk88
Posts: 1
Joined: Thu Jul 18, 2019 5:20 pm

Project Idea getting feedback before I begin

Thu Jul 18, 2019 5:41 pm

I was considering creating a system that could e-mail me if a call light is on more than "x" amount of time would a pi be able to hold up against the electrical requirements of the call system?

For those who do not know a call system call light is a device used to notify nursing staff in nursing homes and hospitals that an individual needs assistance. They push a button a light is then turned on above their room door, lit on a board at a nurse station, and a alarm (beep) is triggered as well.

I often have complaints of it not being answered or not answered within the 10 minutes we are supposed to answer it.

I have about 34 call lights per wing tied into a call board that lights at the nurses station so I was wondering would 1 pi be able to do this or would it be one per light? Would it be difficult for the pi to record and send the time on and off of each light?

**Expanding from that or in a different manner would it be able to either through a display or some method, notify the time of each light that was turned on so if you walk around the corner and 6 are on you know who to address first??**

User avatar
omegaman477
Posts: 148
Joined: Tue Feb 28, 2017 1:13 pm
Location: Sydney, Australia

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 8:27 am

I would start by thinking about machine vision. Have the Pi Camera look at the indicator board, and look for the lights coming on. The various machine vision libraries for the Pi have support for this sort of basic detection.

Failing that it would mean attaching a small photodiode to each call light, messy.

The simplest would be to listen for the buzzer and then email you, but this would not determine what room.
..the only thing worse than a stupid question is a question not asked.

pcmanbob
Posts: 6960
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 8:30 am

Hi.

So first of there are only 26 gpio pins that you can use so you would need to add more using for example a MCP23017 or multiplex the inputs.


Secondly the pi gpio works at 3.3v and I suspect your call light system will be running on a much higher voltage and possibly even mains AC, so you would need an interface between the call lights and the pi gpio.

I suggest you look at the hardware that already exists before proceeding with your project and decide if you can handle the design of such an interface , remembering if you are working with mains voltages there are a lot of safety issues,

The actual program could be written in python which would also be capable of sending your email,

and finally there may be legal implications regarding a user built device being used in a care home or hospital .
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

User avatar
Burngate
Posts: 6013
Joined: Thu Sep 29, 2011 4:34 pm
Location: Berkshire UK Tralfamadore
Contact: Website

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 9:59 am

adammk88 wrote:
Thu Jul 18, 2019 5:41 pm
...
I often have complaints of it not being answered or not answered within the 10 minutes we are supposed to answer it.
...
Am I to understand you to be the member of nursing staff who would be answering, or are you more responsible for the call system itself?
If the former, it may be worthwhile talking to the latter, who may know what's involved with the system
**Expanding from that or in a different manner would it be able to either through a display or some method, notify the time of each light that was turned on so if you walk around the corner and 6 are on you know who to address first??**
If you're approaching the nurses station and see 6 lights there, and want to know which came on first, you'll probably need a separate display with a count-up clock for each.

If you're turning a corner into a wing and see 6 doors with lights, then to find which came first could need a rebuild of the whole system.

gordon77
Posts: 4178
Joined: Sun Aug 05, 2012 3:12 pm

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 10:15 am

omegaman477 wrote:
Fri Jul 19, 2019 8:27 am
I would start by thinking about machine vision. Have the Pi Camera look at the indicator board, and look for the lights coming on. The various machine vision libraries for the Pi have support for this sort of basic detection.

Failing that it would mean attaching a small photodiode to each call light, messy.

The simplest would be to listen for the buzzer and then email you, but this would not determine what room.
I think a camera is a good solution. Here's a mockup using opencv looking at 48 areas of a video frame. The GREY numbers are the average brightness of each area, and the RED number the room number. The YELLOW x shows there has been a detection for that room, and an email sent, it won't send another for that room until its been reset by clicking on the screen.

The box positions could be set to match a light board display.

The email simply says

Room No 13 at 190719-152918
Attachments
rooms.jpg
rooms.jpg (48.69 KiB) Viewed 369 times
Last edited by gordon77 on Fri Jul 19, 2019 3:39 pm, edited 4 times in total.

PiGraham
Posts: 3613
Joined: Fri Jun 07, 2013 12:37 pm
Location: Waterlooville

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 10:28 am

adammk88 wrote:
Thu Jul 18, 2019 5:41 pm

I have about 34 call lights per wing tied into a call board that lights at the nurses station so I was wondering would 1 pi be able to do this or would it be one per light? Would it be difficult for the pi to record and send the time on and off of each light?

**Expanding from that or in a different manner would it be able to either through a display or some method, notify the time of each light that was turned on so if you walk around the corner and 6 are on you know who to address first??**
I assume this is an older existing system. I would expect modern call systems to provide that sort of functionality.

Given that a call system is important for patient safety I suggest you do nothing that could interfere with it's normal operation. Therefore don't connect to it electrically.

Using a camera to look at the board at the Nurse station could be a good option in that it is non-contact and one device covers a lot of lights.

It might help if you posted an image of the board with the lights (ideally with some of them on).


Basically capture still images of the bord and sample pixel values in cells of a grid aligned with the lamps.

Alignment needs thought. Can the camera be so fixed that the alignment is very stable? Does the program have to find the call board in the image, align the grid to it each time it scans?

Do you find individual lamps from their appearance and work out the grid from lamp positions?

A higher value would be a lamp that is on. Possibly measure the difference between a bright level in the cell and a background level. Maybe 10% and 90% percentiles. That adapts to changes in ambient light.

You should be able to get status of every light on the board every few seconds or less.

Timing lamp on/off events is simple once you have the detection and identification of lamps working.
You could also track lamps long term and detect which calls are due a test or which lights are faulty (because they have not been seen on for a long a time).

PiGraham
Posts: 3613
Joined: Fri Jun 07, 2013 12:37 pm
Location: Waterlooville

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 10:30 am

Burngate wrote:
Fri Jul 19, 2019 9:59 am

If you're turning a corner into a wing and see 6 doors with lights, then to find which came first could need a rebuild of the whole system.
Good points, but if the idea is to send notification emails those emails can give room numbers and times and a sorted list.

gordon77
Posts: 4178
Joined: Sun Aug 05, 2012 3:12 pm

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 10:50 am

PiGraham wrote:
Fri Jul 19, 2019 10:28 am



Basically capture still images of the board and sample pixel values in cells of a grid aligned with the lamps.

Just like I did in my example

PiGraham
Posts: 3613
Joined: Fri Jun 07, 2013 12:37 pm
Location: Waterlooville

Re: Project Idea getting feedback before I begin

Fri Jul 19, 2019 11:16 am

gordon77 wrote:
Fri Jul 19, 2019 10:50 am
PiGraham wrote:
Fri Jul 19, 2019 10:28 am



Basically capture still images of the board and sample pixel values in cells of a grid aligned with the lamps.

Just like I did in my example
Yes, like that, or some variant of that.

gordon77
Posts: 4178
Joined: Sun Aug 05, 2012 3:12 pm

Re: Project Idea getting feedback before I begin

Wed Jul 24, 2019 10:14 am

I know the OP hasn't been back but I had a go at this.

WARNING this is proof of concept NOT for use in a care or other vital system.

It simply monitors lights / leds using a Pi Camera.

It can monitor upto 48 leds, set for 34, and will list, in time order, the active ones and how long they have been ON. If the duration exceeds a set time it will set them RED, and can send an email. It also logs all events to a daily log eg 20190724.txt. + means coming event, - means going event followed by the duration it was on.

At present it simply compares the leds against a set brightness trigger level.

The monitoring points can be moved by clicking on them and then clicking on the new position.

Code: Select all

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Press RIGHT Mouse button on picture to EXIT
# Press LEFT Mouse button to move a box, click on one box to move then click on new position.

import random
import numpy as np
import cv2
import time
import datetime
import os,sys
import math
import smtplib, ssl

# sending emails, set to 1 to enable
send_email = 0

#detection window size
window = 15

# number of detection areas 
areas = 34

# set triggers level
trigger = 100

# set alarm period (MINUTES)
alarm = 10

# set camera framerate
framerate = 30

# set camera contrast
contrast = 100

# set camera brightness
brightness = 35

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from email.mime.image import MIMEImage

def sendMail(data):
    port = 465  # For SSL
    smtp_server = "smtp.gmail.com"  # Enter email server
    sender_email = "xxx@xxx.xxx"    # Enter your address
    receiver_email = "yyy@yyy.yyy"  # Enter receiver address
    password = "zzzzzzzz"           # Enter email password
    message = data

    context = ssl.create_default_context()
    with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
        server.login(sender_email, password)
        server.sendmail(sender_email, receiver_email, message)    
# initialise pi camera
if os.path.exists('/dev/video0') == False:
  path = 'sudo modprobe bcm2835-v4l2 '
  os.system (path)
  time.sleep(1)

# initialise variables
cv2.namedWindow('Monitoring Panel')
q = np.zeros((600,384,3), np.uint8)
r = np.zeros((120,640,3), np.uint8)
points = [0]*100
pointz = [0]*100
times = [0]*50
triggers = [trigger]*50
triggered = [0]*50
cleared = [0]*50
emailed = [0]*50
move = 0
log_list = ["-"]*50

# Mouse. LEFT button to move boxes, RIGHT button to EXIT
def point(event, x, y, flags, param):
    global triggered, window , move, store, points, pointz, areas, times, cleared
    if event == cv2.EVENT_RBUTTONDOWN:
        cv2.destroyAllWindows()
        sys.exit()
    if event == cv2.EVENT_LBUTTONDOWN:
        if move == 0:
           minm = 1000
           for j in range (0,areas*2,2):
               temp = math.sqrt((abs(points[j] - y) * abs(points[j] - y) + abs(points[j+1] - x) * abs(points[j+1] - x)))
               if temp < minm:
                   minm = temp
                   store = j
           move = 1
        elif move == 1:
           points[store] = y - int(window/2)
           points[store+1] = x - int(window/2)
           move = 0
           pointz[:] = points[:]
           for j in range (0,areas*2,2):
               pointz[j] = pointz[j] + int(window/2)
               pointz[j+1] = pointz[j+1] + int(window/2)
           with open('points2.txt', 'w') as f:
               for item in pointz:
                   f.write("%s\n" % item)
        

# setup mouse callback               
cv2.setMouseCallback('Monitoring Panel',point)

# check points2.txt exists, if not then write default values
if not os.path.exists('points2.txt'):
  counter = 0
  for x in range (0,6):
    for y in range (0,8):
        points[counter] = ((x*80) + 40)
        points[counter+1] = ((y*80) + 40)
        counter +=2
  with open('points2.txt', 'w') as f:
      for item in points:
          f.write("%s\n" % item)
          
# read points2.txt
points = []
with open("points2.txt", "r") as file:
   line = file.readline()
   while line:
      points.append(line.strip())
      line = file.readline()
points = list(map(int,points))
for x in range (0,areas*2,2):
    points[x] = points[x] - int(window/2)
    points[x+1] = points[x+1] - int(window/2)

now = datetime.datetime.now()
logstamp = now.strftime("%Y%m%d")
if os.path.exists(logstamp + '.txt'):
    with open(logstamp + ".txt", "r") as file:
        line = file.readline()
        while line:
           log_list.append(line.strip())
           line = file.readline()
    log_list.reverse()
    if len(log_list) > 50:
        log_list = log_list[0:49]
    for k in range(0,42):
        cv2.rectangle(q, (180,k*18),(600,(k*18)+20), (0,0,0),-1)
        cv2.putText(q,log_list[k], (185,10 + (k * 14)), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (130, 130, 130),1)
    
# start the video stream
vs = cv2.VideoCapture(0)
path = 'v4l2-ctl -p ' + str(framerate)
os.system (path)
path = 'v4l2-ctl -c contrast=' + str(contrast)
os.system (path)
path = 'v4l2-ctl -c brightness=' + str(brightness)
os.system (path)
time.sleep(1.0)


timer = 0

# main loop
while True:

    a = random.randint(1,10001)
    if a > 9980:
       GPIO.output(Leds[random.randint(0,3)],GPIO.HIGH)

    if a < 2:
       GPIO.output(Leds[random.randint(0,3)],GPIO.LOW)
      
    # read video frame
    ok, img = vs.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # check for triggered lights every frame 
    for box in range (0,areas*2,2):
        windowed = gray[points[box]:points[box]+window, points[box+1]:points[box+1]+window]
        average = np.average(windowed)
        
        # display average levels to help setup
        cv2.putText(img,str(int(average)), (points[box+1] + 30, points[box] + 20 ), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (75, 75, 75),1)
        
        # check for lights ON
        if average > triggers[int(box/2)] and triggered[int(box/2)] == 0:
            now = datetime.datetime.now()
            timestamp = now.strftime("%Y/%m/%d %H:%M:%S")
            triggered[int(box/2)] = timestamp
            times[int(box/2)] = time.time()
            cleared[int(box/2)] = 0
            logstamp = now.strftime("%Y%m%d")
            with open(logstamp + '.txt', 'a') as f:
                if int(box/2) < 9:
                    item = "0" + str(int(box/2)+1) + " : " +  str(timestamp) + " +"
                else:
                    item = str(int(box/2)+1) + " : " +  str(timestamp) + " +"
                f.write("%s\n" % item)
            log_list.insert(0,item)
            del log_list[-1]
            for k in range(0,42):
                cv2.rectangle(q, (180,k*18),(600,(k*18)+20), (0,0,0),-1)
                cv2.putText(q,log_list[k], (185,10 + (k * 14)), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (130, 130, 130),1)
        # check for lights going OFF
        if triggers[int(box/2)] > average and triggered[int(box/2)] != 0:
            now = datetime.datetime.now()
            timestamp = now.strftime("%Y/%m/%d %H:%M:%S")
            cleared[int(box/2)] = timestamp
            triggered[int(box/2)] = 0
            emailed[int(box/2)] = 0
            logstamp = now.strftime("%Y%m%d")
            with open(logstamp +'.txt', 'a') as f:
                if int(box/2) < 9:
                    item = "0" + str(int(box/2)+1) + " : " + str(timestamp) + " - " + str(int((time.time() - float(times[int(box/2)]))/60))
                else:
                    item = str(int(box/2)+1) + " : " + str(timestamp) + " - " + str(int((time.time() - float(times[int(box/2)]))/60))
                f.write("%s\n" % item)
            times[int(box/2)] = 0
            log_list.insert(0,item)
            del log_list[-1]
            for k in range(0,42):
                cv2.rectangle(q, (180,k*18),(600,(k*18)+20), (0,0,0),-1)
                cv2.putText(q,log_list[k], (185,10 + (k * 14)), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (130, 130, 130),1)

    abc = ['x']*35
    count2 = 0
    cv2.rectangle(q, (0,0),(180,600), (0,0,50),-1)
    data =""
    for z in range (0,areas*2,2):
        if triggered[int(z/2)] != 0 and cleared[int(z/2)] == 0:
            room = str(int(z/2)+1)
            if int(z/2) < 9:
                room = "0" + str(int(z/2)+1)
            abc[count2] = str(triggered[int(z/2)]) + "  " + room + str(times[int(z/2)])
            count2 +=1
            abc.sort()
    for z in range (0,count2):
          duration = int((time.time() - float(abc[z][23:39]))/60)
          if duration > 999:
              duration = 999
          if duration >= alarm: 
              cv2.putText(q,abc[z][0:23] + "  " + str(int(duration)) , (2,30 + int(z) * 17), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255),1)
              if send_email == 1:
                  if emailed[int(abc[z][21:23])-1] == 0:
                      data = abc[z][0:23] + " " + str(int(duration))
                      sendMail(data)
                      print ("Emailed :", data)
                      emailed[int(abc[z][21:23])-1] = 1
          else:
              cv2.putText(q,abc[z][0:23] + " " + str(int(duration)) , (2,30 + int(z) * 17), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 200, 200),1)
        
    # draw boxes
    data2 = ""
    for z in range (0,areas*2,2):
        cv2.rectangle(img, (0,0), (639,479), (100,100,100), 2)
        # draw boxes
        cv2.rectangle(img, (points[z+1],points[z]), (points[z+1]+window,points[z]+window), (0,0,200), 1)
        # show yellow box to be moved
        if move == 1 and store == z:
            cv2.rectangle(img, (points[z+1],points[z]), (points[z+1]+window,points[z]+window), (0,200,200), 1)
        # show room numbers
        if triggered[int(z/2)] != 0: 
            cv2.putText(img,str(int(z/2) + 1), (points[z+1], points[z] + window + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 200, 200),2)
        else:
            cv2.putText(img,str(int(z/2) + 1), (points[z+1], points[z] + window + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 155),2)
        cv2.putText(q,"    Date        Time   Rm Dur", (0, 11), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 200, 200),1)
            
    # show frame
    now = datetime.datetime.now()
    timestamp = now.strftime("%Y/%m/%d %H:%M:%S")
    cv2.rectangle(r, (0,0), (400,50), (0,0,0), -1)
    cv2.putText(r,timestamp, (0, 31), cv2.FONT_HERSHEY_SIMPLEX, 1, (200, 200, 200),1)
    
    ver = np.vstack((img,r))
    hor = np.hstack((ver,q))
    cv2.imshow('Monitoring Panel',hor)
    cv2.waitKey(1)
Attachments
panel2.jpg
panel2.jpg (58.76 KiB) Viewed 274 times

Return to “Automation, sensing and robotics”