Thursday, August 6, 2009

My Take on SageTV Server Power Savings

I've been working off & on with the media server's power management. Since we have a DirecTiVo, most of our live viewing is done on that along with some recording, so the Sage server doesn't need to be online unless we're watching some recorded content from it or it's recording. So I can really keep this thing powered down 70% of the time, and almost 90% of the time since it's summer. So I spent some more time figuring out when SageTV is being used and came up with this write up. My solution, like our home automation system, integrates a lot of separate pieces to get things just right.

Let's get to it. First off, as in my previous post, we use the exported sage schedule. Grab this Perl file and save it as a .pl file. The script is fairly simple. It takes a command line argument, the path to the schedule file, and figures out what hours of the day SageTV is recording. It puts that info into a mySQL database called mystuff with username and password as the login credentials. You don't have to use mySQL, that's just what I use to pass data between different components of our system.

The next step involves our xPL Plugin for SageTV and your favorite xPL scripting engine. The engine we use is our homebrew xPL sCU - an xPL bridge to starCOMUltra, the HA software we use. With the xPL plugin for Sage, you can query it for which clients & extenders are currently playing media (or you can rely on the hidden feature where the plugin will check the playing status whenever it receives any xPL message - it will send an update only if the status has changed). In xPL sCU, I've scripted up logic for processing those updates:

function xPLReceived(e,schema,source,dest,msgtype) {
switch(schema.toLowerCase()) {
case "":
if (schema.toLowerCase()=="media.mptrnspt") {
mpName=e.XplMsg.GetParam(1, "mp");
mpCommand=e.XplMsg.GetParam(1, "command");
mpStatus = mySQLQuery("locals","value","SagePlayerStatus");
switch (mpName) {
case "LR":
case "FR":
case "Master":
if (mpCommand=="play") {
mpStatus=mpStatus | Math.pow(2,mpID);
} else {
mpStatus=mpStatus & (7-Math.pow(2,mpID));
if (mpStatus==0) {
if (mpStatus!=0) {

What the snippet does is process xPL messages about the media players' state. If any player is in use, it clears the SageClientIdle flag in starCOMUltra. If a player becomes idle, it checks to see if all the players are idle and starts a 20 minute timer. Elsewhere in the code (not shown) is if that timer expires and all players are still idle, the SageClientIdle flag is set. You can choose your own idle timer length.

Now we have the player and recording status, but wait, what if I'm using the server for some other purpose? The only way I'd be using the server is via remote desktop, so i set up an EventGhost macro on the Sage server to send xPL messages when an RDP session is initiated or closed. A timeout period after a session is closed will determine if that aspect of the server is idle.

Finally, we have all the pieces in the place. In starCOMUltra, where everything comes together, we have this piece of code that runs hourly (along with the script):

// to prevent unneeded throttling, we'll check if sage is currently
// recording or will need to in the next 3 hours
for (i=0;i<4;i++) {
if (mySQLQuery2("sagesched","value","hour",TimeHour()+i)==1) {
// check if media server is awake and no RDP sessions open and no recordings
// for the next 3 hours and no players in use - then 10 after the hour
// we'll put the server to sleep
if (mySQLQuery("locals","value","MediaAwake")==1 && \
mySQLQuery("locals","value","mediaRDP")==0 && \
Devices.Flags.Item("SageClientIdle").State==1) { \
sageRecord==0 && mins==10) {
LogDevice("# stop sage server");

To wake up the server manually, all our viewing areas have a 3Com Audrey touchscreen nearby. It has a screen to wake up the media server which takes a few minutes. Not perfect, but like I said, we use the DirecTivo for most of the on demand TV watching. Plus, most of the time, we watch recordings during prime time and the server is already on.

"That's all!" ;) Obviously, this is very specific to our setup and situation, but hopefully there are ideas and code bits that may be useful to you.

No comments:

Post a Comment