#include #include enum { Hitmout = 60 * 60, // power off time out (secs) Lotmout = 60, // lights off Ival = 5, // check interval (secs) // power states Sunknown = 0, Sidle, // no who, no pwr Son, // who, pwr Stmout, // pwr timing out Nstates, }; typedef struct Cmd Cmd; typedef struct State State; typedef int (*Statef)(Cmd* c, State* s); struct State { vlong gonetime; int who; int lastwho; vlong now; }; struct Cmd { vlong gonetime; char* file; int state; int last; int tmout; Statef func[Nstates]; }; int getx10(char* f) { int fd; char buf[10]; int n; fd = open(f, OREAD); if (fd < 0) return -1; n = read(fd, buf, sizeof(buf)-1); if (n < 0){ close(fd); return -1; } buf[n] = 0; close(fd); if (strcmp(buf, "on") == 0) return 1; else return 0; } void setx10(char* f, char* to) { int fd; int n; if (f == nil) return; fd = open(f, OWRITE); if (fd < 0){ fprint(2, "%s: error: %s -> %s: %r\n", argv0, f, to); syslog(0, "x10a", "%s: open error: %s -> %s: %r\n", argv0, f, to); return; } n = write(fd, to, strlen(to)); close(fd); if (n < 0) syslog(0, "x10a", "%s: write error: %s -> %s: %r\n", argv0, f, to); } static void switchdev(char* file, char* what, int tmout) { if (tmout > 0){ syslog(0, "x10a", "%s: switching %s" " %s in %d minutes", argv0, what, file, tmout/60); } else { syslog(0, "x10a", "%s: switching %s %s now", argv0, what, file); setx10(file, what); sleep(1000); } } void setvol(char* file, int val) { int fd; fd = open(file, OWRITE); if (fd < 0) return; syslog(0, "x10a", "%s: adjusting %s to %d", argv0, file, val); fprint(fd, "audio out %d\n", val); close(fd); } int getvol(char* file) { char buf[100]; int fd; int n; int l; fd = open(file, OREAD); if (fd < 0) return -1; n = read(fd, buf, sizeof(buf)-1); close(fd); if (n < 0) return -1; buf[n] = 0; l = strlen("audio out "); if (strncmp(buf, "audio out ", l) != 0) return 70; return atoi(buf + l); } static int terminit(Cmd* c, State* s) { if (s->who){ switchdev(c->file, "on", 0); return Son; } else { s->gonetime = s->now; switchdev(c->file, "off", c->tmout); return Stmout; } } static int volinit(Cmd* c, State* s) { if (c->last < 0) c->last = getvol(c->file); if (s->who){ return Son; } else { return Stmout; } } static int nvolinit(Cmd* c, State* s) { c->last = getvol(c->file); if (s->who){ if (c->last > 40) setvol(c->file, 40); return Son; } else { if (c->last > 0) setvol(c->file, c->last); return Sidle; } } static int termidle(Cmd* c, State* s) { if (s->who && !s->lastwho){ switchdev(c->file, "on", 0); return Son; } else return Sidle; } static int volidle(Cmd* c, State* s) { if (c->last < 0) c->last = 70; if (s->who && !s->lastwho){ setvol(c->file, c->last); return Son; } else return Sidle; } static int nvolidle(Cmd* c, State* s) { if (s->who && !s->lastwho){ c->last = getvol(c->file); if (c->last == 0){ sleep(1000); c->last = getvol(c->file); } if (c->last > 70) setvol(c->file, 70); return Son; } else return Sidle; } static int termon(Cmd* c, State* s) { if (!s->who && s->lastwho){ switchdev(c->file, "off", c->tmout); return Stmout; } else return Son; } static int volon(Cmd* c, State* s) { if (!s->who && s->lastwho){ c->last = getvol(c->file); return Stmout; } else return Son; } static int nvolon(Cmd* c, State* s) { if (!s->who && s->lastwho){ if (c->last == 0){ c->last = getvol(c->file); } if (c->last > 0) setvol(c->file, c->last); return Sidle; } else return Son; } static int termtmout(Cmd* c, State* s) { if (s->who && !s->lastwho){ switchdev(c->file, "on", 0); return Son; } else if (s->gonetime > 0 && s->now - s->gonetime >= c->tmout){ switchdev(c->file, "off", 0); c->gonetime = 0; // no more power offs until he cames return Sidle; } else return Stmout; } static int voltmout(Cmd* c, State* s) { if (s->who && !s->lastwho){ if (c->last == 0) c->last = 70; setvol(c->file, c->last); return Son; } else if (s->gonetime > 0 && s->now - s->gonetime >= c->tmout){ c->last = getvol(c->file); setvol(c->file, 0); s->gonetime = 0; // no mutes until he cames return Sidle; } else return Stmout; } Cmd tcmd = { 0LL, nil, Sunknown, -1, Hitmout, {terminit, termidle, termon, termtmout} }; Cmd lcmd = { 0LL, nil, Sunknown, -1, Lotmout, {terminit, termidle, termon, termtmout} }; Cmd vcmd = { 0LL, nil, Sunknown, -1, Lotmout, {volinit, volidle, volon, voltmout} }; Cmd ncmd = { 0LL, nil, Sunknown, -1, Lotmout, {nvolinit, nvolidle, nvolon, nil} }; Cmd cmds[100]; int ncmds; void usage(void) { fprint(2, "usage: %s " "[-t term] [-n vol] [-v vol] [-l light] whofile\n", argv0); exits("usage"); } void main(int argc, char* argv[]) { State s; char* whof; Cmd* cp; int i; ARGBEGIN{ case 't': cmds[ncmds] = tcmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; case 'v': cmds[ncmds] = vcmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; case 'n': cmds[ncmds] = ncmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; case 'l': cmds[ncmds] = lcmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; default: usage(); }ARGEND; if (argc != 1 || ncmds == 0) usage(); whof = argv[0]; memset(&s, 0, sizeof(s)); for(;;){ sleep(Ival * 1000); s.now = time(nil); s.lastwho = s.who; s.who = getx10(whof); if (s.who < 0){ syslog(0, "x10a", "%s: can't read %s", argv0, whof); continue; } if (s.who != s.lastwho){ if (s.who){ for (i = 0; i < ncmds; i++) cmds[i].gonetime = 0; //syslog(0, "x10a", "%s: %s came", argv0, whof); s.gonetime = 0; } else { for (i = 0; i < ncmds; i++) cmds[i].gonetime = s.now; //syslog(0, "x10a", "%s: %s gone", argv0, whof); s.gonetime = s.now; } } for (i = 0; i < ncmds; i++){ cp = &cmds[i]; assert(cp->state >= 0 && cp->state < Nstates); cp->state = cp->func[cp->state](cp, &s); } } }