HOW-TO Idle detection on XBMC server running squeezecenter
#1
Idle detection on XBMC:

My server runs a variety of services including XBMC, squeezecenter and a squeezeslave client. I also use it as a file server with my main access being through ssh. I wanted a way to shutdown the server down after being idle for a set time period but couldn't see any easy way of doing this as these services don't talk to each other.

After researching many forums I decided to just write my own python script and run it as an upstart service. I'm not a programmer so the code is not pretty, however it does work. I thought it might be useful to others so have posted it here. If anyone has any improvements or suggestions please post below.


How it works:

I set my xbmc to display a screensaver after 2 minutes of inactivity. The screen saver is a slideshow of fanart in /home/username/Fanart. The script checks if xbmc is playing anything from this folder and hence detects if the screensaver is running. The reason for not using the proper xbmc fanart folder is to avoid false positives during normal use of the menus, though the risk of this happening is small.

The script also connects to squeezecenter and checks each player in turn to see if they are paused or stopped. If all players are inactive squeezecenter is considered idle. Note that squeezeboxes being powered on doesn't constitute activity in the below code, however this can easily be changed.

Additionally, if the file /home/username/nosleep exists the script won't shutdown the computer.

The script then checks to see if any ssh connections are currently open. If there are any established connections then shutdown will be prevented.

The script will do the above checks every 30 seconds. Once all systems have been idle for 20 minutes the server will be shutdown.

There's no reason that the code couldn't suspend or hibernate instead of shutdown. Those functions simply don't work on my system which is why I call the shutdown command.

Installation:

Copy the below code into a file called idle.py. Save this in your home directory (if you save it elsewhere you'll need to modify the upstart config file).

Code:
#!/usr/bin/python
import urllib
import os, os.path, sys
import time
from pylms.server import Server
from pylms.player import Player
import subprocess

global sc
sc = Server(hostname="192.168.0.2", port=9090)
sc.connect()

def logprint(message):
  # Prints messages to screen and saves message in log file
  log = '/home/username/idlelog'
  f = open(log, 'a')
  f.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' ' + message + '\n')
  print time.strftime("%Y-%m-%d %H:%M:%S") + ' ' + message
  f.close()
  return 0

def check_slave():
  # Squeezeslave occasionally crashes on my server
  # If this fails to find squeezeslave in the list of players the slave service is restarted.
  # If you don't run a squeezeslave or don't have this problem delete this function.
  try:
    foo = sc.get_player("00:00:00:00:00:01") # MAC of squeezeslave, replace as appropriate
  except:
    os.system('service squeezeslave restart')
    logprint('Slave service not running, service restarted')

def xbmc_active():
  # Checks to see if the xbmc screensaver is running
  # Returns True when screensaver isn't running
  fanart = '/home/username/Fanart'
  try:
    currently_playing = urllib.urlopen('http://192.168.0.2:8080/xbmcCmds/xbmcHttp?command=getcurrentlyplaying').read()
  except:
    logprint('Failed to connect to XBMC')
    return False
  if fanart in currently_playing:
    logprint('XBMC inactive')
    return False
  else:
    logprint('XBMC active')
    return True

def no_sleep():
  # Checks if the no sleep file exists. Use this as a manual override to prevent shutdown
  path = '/home/username/nosleep'
  if os.path.exists(path):
    logprint('Keepalive flag found: %s' % (path,))
    return True
  else:
    logprint('No keepalive flag found')
    return False

def sc_active():
  # Check the status of all squeeze players attached the server
  # Returns true if squeeze players are active
  players = ["00:00:00:00:00:01", "00:00:00:00:00:02", "00:00:00:00:00:03"] # Replace with appropriate MACs
  check_slave() # If you don't run any squeezeslaves this line can be deleted.
  idle = 1
  try: dp = sc.get_players()
  except: logprint('Connection to SC failed')
  for player in players:
    try:
      foo = sc.get_player(player)
      if foo.get_mode() not in ['stop','pause']: idle = 0
    except:
      pass
  if idle == 1:
    logprint('No squeezeboxes currently active')
    return False
  else:
    logprint('Squeezeboxes currently playing')
    return True

def ssh_active():
  # Check if any ssh connections are open to the server
  connections = subprocess.Popen(['lsof','-i','-n','-P'], shell=False, stdout=subprocess.PIPE).communicate()[0].split('\n')
  lines = process.split('\n')
  i=0
  for line in connections:
    if all(x in line for x in ['ssh','ESTABLISHED','username']):
      i+=1
  if i:
    logprint('%i SSH connection(s) to server active' % i)
    return True
  else:
    logprint('No active ssh connections')
    return False

def shutdown():
  # Shutdown squeezeboxes and bring down the server
  logprint('System has been idle for set time period, shutting down...')
  sc.get_player("00:00:00:00:00:02").set_power_state(False) # This is to turn off any squeezeboxes. Replace MAC as appropriate.
  sc.get_player("00:00:00:00:00:02").set_power_state(False)
  os.system('shutdown -P now') # If hibernate or standby work this could be replaced with pm-suspend or pm-hibernate
  os._exit()


def idle_loop(idle,idle_begin):
  # Main idle detection loop
  idle_time = 60*20 # Amount of time system is to be idle before shutdown
  sleep_time = 30 # Time between loop runs
  time.sleep(sleep_time)
  if idle > idle_time:
    idle = None
    shutdown()
  if (no_sleep() == False) and (xbmc_active() == False) and (sc_active() == False) and(ssh_active() == False):
    if idle_begin == None: idle_begin = time.time()
    idle = int(time.time() - idle_begin)
    logprint('All systems idle, system has been idle for %s seconds\n\n' % str(idle))
    idle_loop(idle,idle_begin)
  else:
    logprint('System active\n\n')
    idle_loop(0,None)

idle_loop(None,None)

The above code requires modification to get it working on your system:

Replace all instances of username with your username.

Replace MAC addresses as appropriate for your hardware.

Modify the paths for logging, fanart location and no_sleep to suit your system. Optional

Change the timers to suit. Note these are measured in seconds, not minutes.


Next create a the file /etc/init/idle.conf and paste the following into it.

Code:
# Idle detection

description "idle detection for XBMC & squeeze"

start on runlevel [2345]

pre-start script
  sleep 60
end script

exec python /home/tungsten/idle.py

This will start the script 60 seconds after boot. You don't want it starting too quickly as the code requires the network to be active. It will exit if it looses the network.

Usage:

To check if the script is running ok type:

Code:
sudo service idle status

This should return something like

Code:
idle start/running, process 1896

To monitor what the script is up to the following can be used:

Code:
tail -f /home/username/idlelog
Reply
#2
This is very interesting. I just started working with squeezeslave this past week. I'm setting up a second system in my house and will be running XBMC and squeezeslave on it. I was using a squeezebox for music in that room, but for various reasons I want to eliminate that as a source and just use the PC. Today I worked through getting the audio configuration right and getting the auto-start to work correctly for squeezeslave. Now I'm wrestling with the issue of whether or not to leave the PC on all the time or put it to sleep. And here I stumbled across this post while looking around for info on the audio settings I needed.

One thing you can try for the startup rather than a sleep command is something like the following:
Code:
start on (starting lightdm and net-device-up IFACE!=lo)
I use that for xbmcbuntu's start line so that xbmc doesn't start prior to the network interface being up. I found this because either nmbd.conf or smbd.conf in the init file left that line off and on my other system this caused issue with network shares showing up correctly as the service didn't even start. Obviously lightdm isn't required in this case, but that'll give you some ideas.

Now with mine I'm only running xbmc and squeezeslave, another system is the server and that is always on. Now I'd have to figure out if I could get this to use sleep or hibernate, and then get wake-on-lan to work. I know how to get IR over USB to wake it up, but I would want the PC to respond if music is started with squeezeserver.
Reply

Logout Mark Read Team Forum Stats Members Help
HOW-TO Idle detection on XBMC server running squeezecenter0