I am writing a small program for a Museum display that captures a still from a webcam, displays it on screen, waits a few seconds and takes another, loop forever. This all works fine from the command line. However, I also have a need to run this as a service so I can stop and start it remotely, i.e. shut it down when the Museum is closed. When I do use the service - nothing shows up on screen and the syslog says that the service starts and stops repeatedly.
Here is the rough, but working code, for the program
#!/usr/bin/python
import os
import pygame, sys
import time
from timeloop import Timeloop
from datetime import timedelta, datetime
from pytz import timezone, utc
import logging
import subprocess
from pygame.locals import *
import pygame.camera
LOG_LEVEL = logging.DEBUG
LOG_FILENAME = os.path.splitext(os.path.basename(__file__))[0] + '.log'
def customTime(*args):
''' Custom Timezone for logging
'''
utc_dt = utc.localize(datetime.utcnow())
my_tz = timezone("US/Eastern")
converted = utc_dt.astimezone(my_tz)
return converted.timetuple()
# Logging Handlers
file_handler = logging.FileHandler(filename=LOG_FILENAME)
stdout_handler = logging.StreamHandler(sys.stdout)
stderr_handler = logging.StreamHandler(sys.stderr)
log_handlers = [file_handler, stdout_handler, stderr_handler]
# Setup general logging
logging.basicConfig(
format='%(asctime)s | %(levelname)s | %(lineno)d | %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=LOG_LEVEL,
handlers=log_handlers)
# Set the logger to use the custom time format
logging.Formatter.converter = customTime
tl = Timeloop()
#initialise pygame
pygame.init()
pygame.camera.init()
pygame.mouse.set_visible(0)
width = 1920
height = 1080
cam = pygame.camera.Camera("/dev/video0",(width,height))
screen = pygame.display.set_mode((width,height), pygame.FULLSCREEN)
def hide_command_line():
""" This sets the text colour of the command line to black
to hide any screen output
NOTE: this will hide all text output on the command line
- exit and log back in to get it back or type 'reset'.
"""
hide_text_command = 'sudo sh -c\
"TERM=linux setterm -foreground black -clear all > /dev/tty0"'
subprocess.Popen(
hide_text_command,
shell=True,
stdout=subprocess.PIPE)
def show_command_line():
""" This sets the text colour of the command line to white
"""
show_text_command = 'sudo sh -c\
"TERM=linux setterm -foreground white -clear all > /dev/tty0"'
subprocess.Popen(
show_text_command,
shell=True,
stdout=subprocess.PIPE)
@tl.job(interval=timedelta(seconds=7))
def take_picture():
cam.start()
#take a picture
image = cam.get_image()
# Show image
screen.blit(image,(0,0))
pygame.display.update()
cam.stop()
if __name__ == "__main__":
hide_command_line()
tl.start()
running = True
while running:
# other code
event = pygame.event.wait()
if event.type == pygame.QUIT:
running = False # Be interpreter friendly
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
show_command_line()
pygame.display.quit()
pygame.quit()
sys.exit(0)
show_command_line()
pygame.display.quit()
pygame.quit()
sys.exit(0)
And here is the syslog output - which just repeats.
Apr 4 19:51:05 raspberrypi systemd[1]: Stopped SpyCamera.
Apr 4 19:51:05 raspberrypi systemd[1]: Started SpyCamera.
Apr 4 19:51:08 raspberrypi systemd[1]: interactive_service.service: Service hold-off time over, scheduling restart.
Apr 4 19:51:08 raspberrypi systemd[1]: Stopped SpyCamera.
Apr 4 19:51:08 raspberrypi systemd[1]: Started SpyCamera.
Apr 4 19:51:11 raspberrypi systemd[1]: interactive_service.service: Service hold-off time over, scheduling restart.
Apr 4 19:51:11 raspberrypi systemd[1]: Stopped SpyCamera.
Apr 4 19:51:11 raspberrypi systemd[1]: Started SpyCamera.
Other than that there are no errors thrown at all (I removed some try blocks just to see what would happen, maybe I was masking an error message - still no errors).
Just to be complete here is the service.
[Unit]
Description=SpyCamera
After=syslog.target
[Service]
Type=simple
User=root
group=root
WorkingDirectory=/home/pi/spycamera
ExecStart=/usr/bin/python3 /home/pi/spycamera/spycamera.py
Restart=always
RestartSec=2
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.target
From the command line it's just "python3 spycamera.py" as user pi. At the moment I terminate by killing the script (still working on the quit code). If I run the service as pi I get the error in syslog of "SystemError: ioctl(VIDIOC_S_FMT) failure: no supported formats". When the service is run as root the error above "SpyCamera Stared", etc... is what I get.
So what I want to know is why it runs fine from the command line, but not when run at startup from a service. Thanks for any and all help.
Update:
I have updated the code some - lessons from other sites attempting to run pygame from systemd - still no joy. However with the edits to the service from @ingo I get new errors (hence the new code)
File "/home/pi/spycamera/spycamera.py", line 51, in <module>
Apr 8 14:23:03 raspberrypi python3[680]: windowSurfaceObj =
pygame.display.set_mode((width,height),1,16)
Apr 8 14:23:03 raspberrypi python3[680]: pygame.error: Unable to open
a console terminal