[net.sources] BSR X10 home controller program

campbell@maynard.UUCP (Larry Campbell) (09/14/86)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	REVIEW
#	Makefile
#	x10.1
#	x10.h
# This archive created: Sat Sep 13 22:38:50 1986
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
DESCRIPTION

x10 is a little program for hacking a BSR X10 "Powerhouse" home
control device.  This gizmo, currently sold by DAK (a discount mail
order house) for $49.95, can remotely control lights and appliances
in your house by signaling over the house wiring.  Since most people
know what the X10 system does (see the DAK catalog for details;  Radio
Shack also sells X10 stuff) I won't describe it in detail here.

The gizmo comes with software for IBM PCs, Apples, or Commodores, but
I wanted to hang it off my UNIX box.  So I wrote this program.

The BSR X10 Powerhouse connects to a computer with an RS232 interface.
It can store up to 128 events;  each event can turn on, turn off, or dim
up to sixteen slave units.  The X10 box has a battery backed up clock
which the computer can read, which turned out to be one of its biggest
uses for me -- my computer doesn't have a battery clock.

Each slave unit has a one-letter housecode ranging from A to P (for 16
different codes) and a number from 1 to 16.  x10's command structure
is pretty primitive.  See the man pages for details.

INSTALLATION

Hopefully, the only file that needs to be configured for your
system is the makefile.  You may need to review x10.h and tty.c
if you experience any trouble.

Change BIN to the location of your favorite directory.
Change OWNER to whichever login you want.
Keep the GROUP set to sys.

the DFLAGS line in the makefile needs to be configured as follows:

	add -DVENIX if you are using Venix
	add -DSYSV if you are using System III or V
	add -DMINIEXCH if you are using the DEC mini-exchange
	add -DVIOD if your compiler doesn't have type void
	add -DXDIR=\"fullpath_name/x10\" if you don't want to
		use the default path of the current directory

After changing the makefile for your system, do 'make'.
Next, cd as 'root' to /dev and link the root filesystem
and tty port connected to the 'X10' as follows:
	ln root_fs_special_device x10fs
	ln tty_port x10

The port connected to the x10 should not have a getty running.
The root filesystem needs to be set to group 'sys' and mode 440.
('x10 date' is the only command that requires this.  If you do
not want to do it because you're worried about security, do not
create /dev/x10fs.  All other features of x10 will work.)  The
tty port connected to the x10 needs to be changed to the owner
of the 'X10 device', and the mode needs to be set to 600.

Finially, do 'make install' as root to install x10 in the proper
location, with the proper owner and the proper permissions.

PORTABILITY

This has been tested under VENIX/Rainbow, which is basically V7 (thus
there are no short-identifier problems), and on System V, Release 3.0.
It should run OK under BSD-flavor UNIX.

NOTES

I'm running my X10 through a DEC Mini-Exchange, which is a dumb little
8-port programmable port selector.  (My computer has only one, count 'em,
serial port with modem control, which is why I use the Mini-Exchange.)

There are two VENIX-specific hacks in x10.  First, my routine hangup()
depends on a modification I made to the VENIX tty driver that causes it
to drop DTR if you set the baud rate to zero, and raise it again when
you set the baud rate to a nonzero number.  Most modern flavors of UNIX
have an ioctl or something to do this.  

Second, there are a number of occurrences of:

	sleep(SMALLPAUSE);

where SMALLPAUSE is #defined to be -10.  This is a VENIX-specific hack
that means sleep for 10 60ths of a second, or 1/6th of a second.  This
isn't critical; if VENIX is not defined in the makefile, SMALLPAUSE is 
set to 1.

EXAMPLES

Example contents of an id file:

1	Bedroom switched table lamp
2	Office switched floor lamp
3	Living room ceiling lights
4	Front porch and garrage lights
5	Family room hanging lamp
6	Family room portable radio
7	Thermostat
8	Bedroom protable tv

Example output of the 'x10 dump all' command using the above id file:

    SLOT    UNIT    STATE    ID    DESCRIPTION
       0    c1      Off      001   Bedroom switched table lamp
       1    c2      Off      002   Office switched floor lamp
       2    c3      Off      003   Living room ceiling lights
       3    c4      Off      004   Front porch and garrage lights
       4    c5      Off      005   Family room hanging lamp
       5    c6      Off      006   Family room portable radio
       6    c7      Off      007   Thermostat
       7    c8      Off      008   Bedroom protable tv

   EVENT   STATE    MODE       DAYS        TIME     UNITS
       0   On       Normal     Everyday    21:00    c5
       1   Off      Normal     Everyday    22:30    c1-8
       2   Dim  8   Normal     Everyday    21:15    c3
       3   Off      Normal     Everyday    21:45    c3
       4   On       Today                  21:33    c1
       5   Dim  4   Security   Weekdays    20:15    c2
       6   Off      Normal     Weekend      1:00    c1-2,6-7

- Larry Campbell (maynard!campbell)
  with help from John Chmielewski (rogue!jlc)
  September 1, 1986
SHAR_EOF
fi
if test -f 'REVIEW'
then
	echo shar: "will not over-write existing file 'REVIEW'"
else
cat << \SHAR_EOF > 'REVIEW'
===========================================================================
X10  PowerHouse Product Review			Joseph M. Newcomer
===========================================================================

[I gather from reading this several times that the X10 Powerhouse is
a BSR controller which allows one to turn on and off various electrical
outlets in your house by sendigh digital radio signals through the power
lines to remote switches. -wab]

I bought an X10 PowerHouse with IBM-PC software a while back from the nice
folks at DAK.  I couldn't get it to work, so hadn't reported on it.

What I can now report is success.  The basic problem was the interface
was dead.  This was hard to determine, since pushing an on/off key actually
sent data to the machine, and the machine was clearly sending data to
the PowerHouse controller, but the controller never responded to the computer.
I finally got around to calling them, and got their technical guy on the line.
He had me do a couple experiments and determined that it was dead.  Within
a week I received a new unit with a return letter to return the old (dead) one.

It took a bit more experimental computer science to get it working.  The
documentation told me how to install DOS on my X10 disk, but not how
to install X10 software on my hard disk.  So of course I got it wrong;
I failed to install "X10.DAT".  I'm not sure what this does but it is
critical; without it, the interface still appears to be dead.  (The 
differences was that 'local control' at the interface would actually
activate devices!)  The error message is definitely misleading.  Anyway,
I installed X10.DAT and it worked.

The user interface is rather tasteful.  No silly little house icons with 5
bedrooms and no libraries or computer rooms (as the Radio Shack product) and
you can assign any house/unit code to any device (unlike Radio Shack where you
have to artificially use up all the "A" units to be able to use a "B" unit,
and you can't have multiple assignments to the same code).  I'd have done a
few things differently, but at least they got it really well done.  You can
save configurations on disk files, and load the files, so I now have "normal"
and "away" modes.  You can temporarily "freeze" a request so it is effectively
"turned off" without actually losing the data, although on the whole I prefer
to use different files for this.


It comes with three manuals, all rather detailed but certainly not
complete.  There is an owner's manual which tells how to install
controllers and configure them.  There is the software manual, which
tells how to use the software they deliver with it.  Finally, there
is the programming guide, which gives in nearly-infinitesimal detail
all of the async protocols for actually communicating with it.  This
detail, alas, misses a few key questions and isn't entirely clear
anyway, but most of it appears to be there.  If you have a compulsion
to program it yourself, which I think is largely unnecessary given
the not-bad-at-all software, you may end up on the phone to New
Jersey.  On the other hand, they seem anxious to help.

A Good Buy, in my estimation.  joe 

===========================================================================
Re:DAK BSR X10 Powerhouse Interface			Larry Campbell
===========================================================================

One small contradiction to Joe Newcomer's otherwise accurate review
of the BSR X10 Powerhouse in Info-IBMPC Digest V5 #68.  He said that
it looked like the protocol manual was incomplete, and that anyone
trying to actually write software for the thing would probably have
to make a few phone calls to New Jersey.  (He also wondered why anyone
would want to write such software since the program shipped with the
box was so good.)

I had to write my own software since I am not using an IBM PC running
MS-DOS, but rather a DEC Rainbow running VENIX.  I was able to get my
software working without any calls to New Jersey.  Actually there were
a couple of omissions in the manual, but I was able to figure them out
without any trouble.  All in all, I think the protocol manual is pretty
good.

Another nifty feature of the BSR box that I think Joe failed to mention
is that it contains a battery backed up clock.  Since there isn't a
reasonable way to get a clock into a Rainbow (there are some hacks on
the market at about $125, or more than twice the cost of the BSR box),
I also hacked up a way for my system to query the BSR box at boot time
for the date and time.

All in all, I agree with Joe:  the box is nifty and a bargain at $49.90.

Larry Campbell                             The Boston Software Works, Inc.
					   120 Fulton Street, Boston MA 02109
UUCP: {alliant,wjh12}!maynard!campbell     (617) 367-6846
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
HOME = /usr/campbell
BIN = $(HOME)/bin
GROUP = sys
OWNER = bin

#	set DFLAGS equal to:
#	   -DVENIX	if using VENIX
#	   -DSYSV	if using SYSTEM V
#	   -DVOID	if compiler doesn't understand 'void'
#	   -DMINIEXCH	if using the DEC mini-exchange
#	   -DXDIR=\"fullpath_name/x10\" if not using default of "."
DFLAGS = -DVENIX -DXDIR=\"$(HOME)/X10\" -DMINIEXCH

CFLAGS = -O $(DFLAGS)
LDFLAGS = -z -i
#LIBS = -lc_s		# uncomment if using shared libraries

SRCS =	data.c date.c delete.c diagnostic.c dump.c fdump.c \
	finfo.c fload.c info.c getslot.c message.c miniexch.c \
	monitor.c prints.c readid.c reset.c schedule.c setclock.c \
	tty.c unit.c x10.c xread.c

OBJS =	data.o date.o delete.o diagnostic.o dump.o fdump.o \
	finfo.o fload.o info.o getslot.o message.o miniexch.o \
	monitor.o prints.o readid.o reset.o schedule.o setclock.o \
	tty.o unit.o x10.o xread.o

x10:	$(OBJS)
	cc $(LDFLAGS) -o x10 $(OBJS) $(LIBS)
	if [ -f /usr/bin/mcs ]; then mcs -c x10; fi
	chgrp $(GROUP) x10
	chmod 2755 x10
	chown $(OWNER) x10

$(OBJS): x10.h

install: x10
	mv x10 $(BIN)

lint:
	lint $(DFLAGS) $(SRCS)

shar:	x10.shar.1 x10.shar.2

x10.shar.1:
	shar README REVIEW Makefile x10.[1h] >x10.shar.1

x10.shar.2:
	shar $(SRCS) > x10.shar.2

clean:
	rm -f *.o

clobber: clean
	rm -f x10
SHAR_EOF
fi
if test -f 'x10.1'
then
	echo shar: "will not over-write existing file 'x10.1'"
else
cat << \SHAR_EOF > 'x10.1'
.TH X10 1 local
.SH NAME
.B x10\^
- control program for the BSR X10 Powerhouse
.SH SYNOPSIS
.B x10 data \fIunit-name\fP \fIbinary-state\fP \fIid\fP
.br
.B x10 date
.br
.B x10 delete \fIrequest-type\fP \fIitem-numbers\fP
.br
.B x10 diagnostic
.br
.B x10 dump \fIrequest-type\fP
.br
.B x10 fdump \fIrequest-type\fP
.br
.B x10 finfo \fIrequest-type\fP
.br
.B x10 fload \fIrequest-type\fP
.br
.B x10 info
.br
.B x10 unit \fIunit-specifier\fP \fIstate\fP
.br
.B x10 monitor
.br
.B x10 reset [\fIhousecode\fP]
.br
.B x10 schedule \fIunit-specifier\fP \fIday-specifier\fP \fItime\fP \fIstate\fP
.br
.B x10 setclock
.SH DESCRIPTION
.I x10
is a little program for controlling a BSR X10 "Powerhouse" home
control device.  The BSR X10 can remotely control lights and appliances
in your house by signalling over the house wiring.
.PP
The BSR X10 Powerhouse connects to a computer with an RS232 interface.
It can store up to 128 events;  each event can turn on, turn off, or dim
up to sixteen slave units.  The X10 box has a battery backed up clock
which the computer can read.
.PP
Slave units are identified by a one-letter housecode ranging from A to P (for 16
different codes) and a number from 1 to 16, for a total of 256 possible
unit codes.
.PP
You could just put a bunch of "x10 unit" commands in your crontab, but
this doesn't work if your system is down for backups, or has crashed,
or if someone's tripped over the RS232 cable and unplugged it, and it
clutters up your crontab something awful.  For most uses, it's much
easier to just load the events into the X10.  You can dump the schedule
into a file (with the \fBx10 fdump\fP command),
and you can have different files for different times of
the year, for before and after Daylight Savings Time, etc.
.PP
X10 unit descriptions are kept in a file called \fBid\fR.  Each
line contains a number (1-255) and a unit description (0-39 characters),
separated by a tab.
The number represents a code that can be stored in the X10 along
with a unit id using the \fBx10 data\fR command.  If the \fBid\fR
file exists, the \fBx10 dump data\fR or \fBx10 dump all\fR commands
will print descriptions for each unit code contained in the file.
.SH COMMANDS
.IP \fBdata\fP \fIunit-name\fP \fIbinary-state\fP \fIid\fP
Loads data into "graphics" storage in X10 box.  Currently used to
record correspondence between id file identifier and unit code,
and current state of unit.
This stuff is incomplete at present.
.PP
.IP \fBdate\fP
Gets current date and time from X10 and displays it in a form suitable
for feeding to \fIdate(1)\fP as input.  Thus, you can set your system clock
by saying "date `x10 date`".
.PP
.IP \fBdelete\fP \fIrequest-type\fP \fIitem-numbers\fP
Deletes the request of type \fIrequest-type\fP with item number
\fIitem-number\fP from X10 memory.
.PP
.IP \fBdiagnostic\fP
Runs the X10 diagnostic and reports the result.  \fBCaution:\fP running
the diagnostic scrambles X10 memory, losing all downloaded events and
data.
.PP
.IP \fBdump\fP \fIrequest-type\fP
Writes a readable description of all events of type \fIrequest-type\fP
on standard output.
.PP
.IP \fBfdump\fP \fIrequest-type\fP
Writes an unreadable description (binary data) of all events of type
\fIevent-type\fP on standard output.  If you redirect this stuff to
a file, you can subsequently feed it to a \fBx10 fload\fP command.
.PP
.IP \fBfinfo\fP \fIrequest-type\fP
Like \fBdump\fP, but reads binary data in \fBfdump\fP format from
standard input, rather than reading data from the X10.
.PP
.IP \fBfload\fP \fIrequest-type\fP
Loads the X10 memory with requests of type \fIrequest-type\fP from
data on standard input in \fBx10 fdump\fP format.
.PP
.IP \fBinfo\fP
Displays current setting of X10's clock and housecode.
.PP
.IP \fBunit\fP \fIunit-specifier\fP \fIstate\fP
Sets the specified unit to the specifed state.
.PP
.SH ARGUMENTS
Most X10 commands require arguments.  They are as follows:
.TP 5
\fIhousecode\fP
housecode is a letter from a-p
.TP 5
\fIid\fP
The identification number of the unit (1-255).  It is used to associate
a description string from the ID file to a specific unit.
.TP 5
\fIitem-number\fP
An X10 event-numbers (0-127) or id-slot (0-255).
.TP 5
\fIbinary-state\fP
id-state is either \fBon\fR or \fBoff\fR
.TP 5
\fIday-specifier\fP
mode-day is in the form: (mode) ([day])
.br
Modes:
.RS 5
 \fBn\fRormal  (days)
.br
	\fBse\fRcurity (days)
.br
	\fBtod\fRay
.br
	\fBtom\fRorrow
.RE
Days:
.RS 5
\fBm\fRonday, \fBtu\fResday, \fBwed\fRnesday,
\fBth\fRursday, \fBf\fRriday,
.br
\fBsa\fRturday, \fBsu\fRnday, \fBweekd\fRay,
\fBweeke\fRnd, \fBe\fRveryday
.RE
.TP 5
\fIunit-name\fP
A name for a single unit in the form: (housecode)(unit-number)
.RS 5
housecode is a letter from a-p
unit-number is a number from 1-16
.RE
.TP 5
\fIunit-specifier\fP
A specifier for one or more units, in the form
(housecode)(unit-number[,unit-number...])
.RS 5
housecode is a letter from a-p
.br
unit-number is a number from 1-16 or a '*' to indicate all units
.RE 3
.TP 5
\fIrequest-type\fP
request is \fBevents\fR or \fBdata\fR for delete, fdump, finfo,
and fload commands
.br
request is \fBevents\fR or \fBdata\fR or \fBall\fR for dump command
.TP 5
\fIstate\fP
state is in the form: (function) ([value])
.RS 5
.B on
.br
.B off
.br
.B dim
(value)
.RS 5
value is a number from 1-16
.RE 3
.TP 5
\fItime\fP
Time is in 24 hour format of the form HH:MM
.SH EXAMPLES
.TP 5
x10 unit a5 on
Turns slave unit A5 on.
.TP 5
x10 unit b7 dim 8
Sets unit B7 to dim level 8 (levels run from 0 to 15, bright to dim)
.TP 5
x10 info
Displays X10 clock time and base housecode
.TP 5
x10 setclock
Sets X10's clock to current time of day (from UNIX)
.TP 5
x10 schedule a3,5 security everyday 17:30 off
Enters an event to turn units A3 and A5 off every day about 17:30
.TP 5
x10 schedule a2 normal wed 5:00 on
Enters an event to turn unit A2 on every Wednesday at 5:00
.TP 5
x10 schedule b8 today 9:00 dim 9
Enters an event to dim unit B8 to level 9 today at 9:00
.TP 5
x10 dump all
Displays all events and data in X10's memory
.TP 5
x10 delete event 12
Deletes event 12 from X10's memory
.TP 5
x10 reset
Clears X10 memory, deletes all events and sets housecode A
.br
(does not clobber clock)
.TP 5
x10 reset c
Clears X10 memory, deletes all events and sets housecode C
.br
(does not clobber clock)
.TP 5
x10 diagnostic
The X10 performs its internal diagnostic routine
.br
(clobbers memory and clock, but not housecode)
.TP 5
x10 fdump data > datafile
Dumps X10 id data into file
.TP 5
x10 fload events <eventfile
Loads X10 event data from file
.TP 5
x10 finfo events < eventfile
Displays events in file produced by x10 fdump
.TP 5
x10 date
Displays date in date(1) input format.
.SH FILES
id - X10 unit description file
.SH AUTHORS
Originally written by Larry Campbell (maynard!campbell).  System V
port, ID file, improved display formats, and other cleanup by John
Chmielewski (rogue!jlc).
.SH SEE ALSO
X10 POWERHOUSE computer interface model no. CP290 programming guide
.br
date(1)
SHAR_EOF
fi
if test -f 'x10.h'
then
	echo shar: "will not over-write existing file 'x10.h'"
else
cat << \SHAR_EOF > 'x10.h'
/*
 * Copyright 1986 by Larry Campbell, 73 Concord Street, Maynard MA 01754 USA
 * (maynard!campbell).  You may freely copy, use, and distribute this software
 * subject to the following restrictions:
 *
 *  1)	You may not charge money for it.
 *  2)	You may not remove or alter this copyright notice.
 *  3)	You may not claim you wrote it.
 *  4)	If you make improvements (or other changes), you are requested
 *	to send them to me, so there's a focal point for distributing
 *	improved versions.
 *
 * John Chmielewski (tesla!jlc until 9/1/86, then rogue!jlc) assisted
 * by doing the System V port and adding some nice features.  Thanks!
 */

/*
 * BSR X-10 "Powerhouse" Computer Interface Definitions
 */

/***********************************************************************/
/* You probably only need to hack this section to reconfigure for      */
/* your system                                                         */
/***********************************************************************/

/* Some lints don't know about the void type */

#ifdef VOID
#define void int
#endif

#define DEVNAME	 "/dev/x10"	/* terminal line X10 box is connected to */
#define ROOTNAME "/dev/x10fs"	/* name of root filesystem */

#ifndef XDIR
#define XDIR "."		/* directory containing X10 files */
#endif

#define IDFILE "/id"		/* description file for X10 modules */

#ifdef  MINIEXCH		/* if talking through a DEC Mini-Exchange */
#define MINIXPORT 3		/* port number X10 gizmo is plugged in to */
#endif

#ifdef  VENIX
#define SMALLPAUSE -10		/* 1/6th of a second sleep(3) (VENIX only) */
#else
#define SMALLPAUSE 1
#endif

#define TIMEOUT 10		/* seconds to wait for data */
#define DTIMEOUT 15		/* timeout for dim and diagnostic commands */

/***********************************************************************/
/*                  End of configuration section                       */
/***********************************************************************/


#define SYNCN 16		/* number of FF chars to send before packet */

#define CHKSUM(buf) chksum(buf, sizeof(buf))

/* Event item as stored in event file */

struct evitem
    {
    unsigned e_num;
    unsigned char e_buf[8];
    };

#define EVSIZE sizeof(struct evitem)

#define EVENTS "events"		/* event data keyword */
#define ETOTAL 128		/* total number of events */
#define ESIZE  8		/* size of event data field */
#define EVCMD  12		/* size of event command */

/* Data item as stored in data file */

struct ditem
    {
    unsigned d_num;
    unsigned char d_buf[2];
    };

#define DISIZE 6	/* sizeof not used as it includes holes */

#define DATA   "data"		/* id data keyword */
#define DTOTAL 256		/* total number of id's */
#define DSIZE  2		/* size of id data field */
#define DICMD  6		/* size of data command */

/* description field structure */

#define DLENGTH 40		/* length of the description field */

struct id
    {
    char describe[DLENGTH];
    };

/* Command codes */

#define SETHCODE	0	/* load house code */
#define DIRCMD		1	/* direct command */
#define SETCLK		2	/* set clock */
#define DATALOAD	3	/* timer/graphics data download */
#define GETINFO		4	/* get house code and clock */
#define GETEVENTS	5	/* get timer events */
#define GETDATA		6	/* get graphics data */
#define DIAGNOSE	7	/* run diagnostic */

#define XMTSYNC		16	/* transmitted sync length */
#define RCVSYNC		6	/* received sync length */

/* House code magic numbers */

#define HC_A	0x60
#define HC_B	0xE0
#define HC_C	0x20
#define HC_D	0xA0
#define HC_E	0x10
#define HC_F	0x90
#define HC_G	0x50
#define HC_H	0xD0
#define HC_I	0x70
#define HC_J	0xF0
#define HC_K	0x30
#define HC_L	0xB0
#define HC_M	0x00
#define HC_N	0x80
#define HC_O	0x40
#define HC_P	0xC0

struct hstruct
    {
    unsigned char h_code;
    char h_letter;
    };

struct nstruct
    {
    char *n_name;
    char n_code;
    };

/* Message definitions */

#define EM_2MANY	"Too many command line arguments"
#define EM_INVCN	"Invalid command name"
#define EM_WNA		"Wrong number of arguments"
#define EM_NMA		"Need more command line arguments"
#define EM_NOCMD	"No command argument specified"

/* External Variables */

extern char *E_2MANY, *E_INVCN, *E_WNA, *E_NMA, *E_NOCMD;
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
Larry Campbell                             The Boston Software Works, Inc.
ARPA: campbell%maynard.uucp@harvard.ARPA   120 Fulton Street, Boston MA 02109
UUCP: {alliant,wjh12}!maynard!campbell     (617) 367-6846