<?xml version="1.0" encoding="utf-8"?><html><head><title>Help for the X10 Controller</title></head><body><h1>Help for the <a href=".">X10 Controller</a></h1><p>The display - below the title - has two rows:</p><dl><dt>Control groups</dt> <dd><p>This is a list of different pages of things to control. The initial page is a list of all devices in the house. The other lists are groups of devices that can be controlled as a unit, and this page. The active page is boldfaced, the others are links to that page.</p></dd> <dt>A row of three columns for each device in the housecode.</dt> <dd><ol><li>First is an "on" button. That turns this device on.</li> <li>The name of the device. If that device was last turend on, the naem is colored <span style="color:green">green</span>. If it was last turned off, it's colored <span style="color:red">red</span>. Otherwise it's the default background color. If something other than the server has changed the power, the server probably has this wrong.</li> <li>An "off" button, to turn the thing off.</li></ol></dd> </dl> </body></html>

;;; Bottom level abstraction - an X10 controller object.;; These map to an X10 controller attached to the computer. They;; support three operations: open, close and and set-device. Since;; these correspond to hardware ("things you can kick") that usually;; can't be used in parallel, they should always be wrapped by an;; agent.(ns x10.controllers [:use [x10.config :only (*controllers*)] [clojure.walk :only (walk)]] [:import gnu.io.CommPortIdentifier [com.micheldalal.x10 CM17A]]);; The tricky part here is that the open should only happen once. We;; can't open things when we build the *devices* structure, as it will;; then happen at compile time, which causes the compile to break.(defprotocol Controller "X10 Controller Modules" (open [this] "Whatever is needed to open the controller and ports") (close [this] "Close & free the port for possible reuse.") (set-device [this code unit state] "Set the device at address code/unit to state"));;; To add a new controller type;; Write the appropriate defrecored that instantiates the Controller;; protocol, then add an entry to the *controller-type-map* to map the;; name used in the config database to the record.(deftype CM17A-controller [^CM17A controller ^String port delay] Controller (open [this] (when-not (.getSerialPort controller) (.setSerialPort controller (.open (CommPortIdentifier/getPortIdentifier port) "Mike's X10 Controller" 2000)) (Thread/sleep (Integer/parseInt delay))) this) (close [this] (.close (.getSerialPort controller)) this) (set-device [this code unit new-state] (.setState controller (first code) (Integer/parseInt unit) new-state) (Thread/sleep (Integer/parseInt delay)) this));;; Map from controller type names to code.;; Note that the keys here must match the types in;; config/*controllers*. There should be one entry for each unique;; controller type. It maps to a function to produce a new controller;; given a port and delay.(def *controller-type-map* {"CM17A" (fn [port delay] (CM17A-controller. (new CM17A) port delay))});;; Map of all available controllers, built from the above and(def *controller-map* (walk (fn [[name module port delay]] {name (agent ((*controller-type-map* module) port delay))}) #(apply merge %) *controllers*))