This document is an overview of the classes in the Gadget-Kit for Java software. For a complete discussion of the classes and API, see the API-docs themselves. This document discusses the "big picture", pointing out design goals, principal classes, features, and relationships.
This toolkit requires a Java implementation compliant with JDK-1.1 or later. Certain parts of the toolkit also require an implementation of the Java Communications API 2.0 for your desired target platform. Known implementations of Java-comm are available from:If you know of other Java-comm implementations for other platforms, you can e-mail me a note and I'll add them to this document.
- Patrick Beard for Mac OS under MRJ 2.1 or higher.
-- With Patrick's permission, I've included this class-library with the Mac OS distribution of the Gadget-Kit. Source for these classes is not included. You can keep an eye on Patrick's web-page for updates, which should just be drop-in replacements for the JAR I've included.- Sun Microsystems for Windows and Solaris.
-- I have NOT INCLUDED any Java-comm class-library with the platform-neutral distribution, so you will have to acquire one appropriate to your platform.This toolkit should work under Java2, though I have not tested this. I have made no effort to avoid deprecated methods, so you may see warnings if you compile with deprecation-warnings enabled.
Under MRJ on Mac OS, this toolkit and applications have been tested under MRJ 2.1.* and 2.2.* on a PowerPC-based machine (a 604e and a dual G4). It has not yet been tested on a 68040-based machine because I lack a Java-comm library for the '040 at this time. Efforts are underway to remedy this, and support for 68040 Macs and MRJ 2.0 is anticipated, but at an undetermined date.
Patrick Beard's Java-comm library has been tested with the Mac's built-in serial-ports and with a 4-port PCI card from MegaWolf. It's also been tested with the Keyspan USB-based serial-port adapter. Other serial-expansion PCI cards and USB devices that provide Comm Toolbox (CTB) support should also work, but your actual mileage may vary.
"X-10" is a trademark owned and licensed by X-10 Inc. When "X-10" or "X10" appears in these documents and source files, it is solely to identify those products of X-10 Inc. or its licensees that conform to the X-10 communication and activation protocols. No other relationship to X-10 Inc., its products, or any of its licensees or their products is intended or implied.This software is not a product of X-10 Inc., nor is it endorsed or approved by them or any other X-10 licensee for use with any X-10-compatible product.
This software may not work with any particular X-10-compatible product or configuration. All risk and liability for any use of this software for any purpose whatsoever lies solely with the user.
1999-Sep-13
- GadgetAction, GadgetTrigger, GadgetGroup, and GadgetLoader added to core gadget package.
- Added all the cyclic-time classes.
- Added all the trigger-parsing classes.
- Added the X-10 Schedule Toy program.
- Revised the previous package structure, so the X-10 and utility classes have moved.
- I forget what else, but there's a lot more than before.
1999-Jul-23
- Gadget.getValueString() is a new method that returns a String formatted for the particular type of a Gadget. This can include measurement units, or can represent the value in any way that a Gadget sees fit. Other classes have been refactored to use this new feature.
- Gadget.disconnect() semantics and explanation have been improved. You can disconnect() a Gadget and continue setting and getting its value. This may seem pointless until you realize how useful it is in an interactive situation where you don't want to keep telling the underlying device to change value. Things like clocks, timers, and other infrequently changed device parameters will find this useful.
- Patrick Beard's latest Java-Comm classes are now included with the Mac OS distribution. These new fixes have little noticeable effect at this time, except that now the serial-port names are sorted alphabetically. This is much nicer when extra serial ports are present, say on a PCI card or USB adapter.
- I've added a couple of classes to represent the X-10/CP290's built-in clock and base house-code -- as settable Gadgets, of course. These are incomplete at this time, and I won't be able to finish them for a few weeks. There's enough to play with, but they are "disconnected" Gadgets that have no effect on the CP290 controller itself. Some of the other classes were extended to support these new additions.
1999-Jul-21
- First public release.
Among other things, I occasionally design and create dedicated microcontrollers. These perform various tasks while connected to the serial-port of a computer. Occasionally, these devices perform independent tasks and only communicate through a serial-port at infrequent intervals. These devices may drive sensors or actuators, and sometimes combine both sensing and actuating in a single unit. A typical architecture puts all the real-time or bit-twiddling tasks in the microcontroller, and lets the attached computer do the rest of the work. I'd like to be able to use Java for some of these projects, even if Java isn't on the microcontroller itself. These microcontrollers often have only 1-2K ROM and 64-128 bytes of RAM, or even less -- not exactly a killer JVM platform. Still, the microcontroller code is often only a fraction of the total project's time and effort.There have also been times when I've needed to integrate a few X-10 modules into a complete system. In the past, it was a custom hack, but it was obvious at the time that a fairly uniform framework for sensors and actuators was possible -- I just didn't have the time at that point.
Lastly, I've worked on projects that used devices as diverse as laser-disc players, A/V switches, lighting controllers, telephone-line interfaces, and DTMF decoders -- sometimes all in the same project. Sometimes it was necessary to allow for different hardware to be added, removed, or updated over the lifetime of the installation, with software also updated from a remote location. A uniform plug-in architecture for the device interfaces would clearly simplify such things, and simplify similar future projects. Uniformity also makes it easier to distribute the development and testing among multiple engineers.
All this went into the initial design of the Gadget-Kit classes, then I let it all soak overnight in a large bucket of well-seasoned restraint. I wanted to keep things as simple as possible, even ruthlessly simple, yet still allow for a wide variety of control and sensing applications. The goal was not to solve every foreseeable problem in every imaginable situation. The most important goal was to provide a simple, solid, understandable, and usable foundation. This foundation could then be extended over time or supplemented with additional classes. Hard real-world experience would guide those extensions, not daydreamed flights of fancy or fits of "cool-featuritis".
I chose X-10 as an actuator example because it's widely available, inexpensive to deploy, and easy to expand. As far as I know there isn't a Java class-library available for it, either -- until now :-). The X-10 computer interfaces (e.g. CP290 and CM11A models) are well known and have well-defined and relatively simple protocols. I only intended to support the direct-control capabilities of these units, not any stored-event or upload/download features. Still, those sophisticated features might be added later, even if I didn't need them immediately.
I chose cyclic-time in general, and minute-of-week in particular, because it's well understood and convenient to use. Common technologies like VCR's, sprinklers, and alarm-systems often have a cycle of at least one week with a precision of one minute. These classes also provide most of the event-scheduling capabilities of the X-10 computer interfaces, making the absence of those in the X-10 classes less painful (if you leave your computer on). Other time-related Gadgets are possible, such as count-down timers, and they may appear in future versions of this toolkit. Or you can define them yourself.
The principal goal was to provide a uniform framework that could represent sensors and actuators of many different kinds. Having worked with many different kinds of devices before, it was also important to provide an architecture where a single centralized controller operated many distinct devices in a hub-and-spokes or hen-and-chicks metaphor. This aspect should only be semi-visible, though, since it is really the individual sensors or actuators that appear in the software model, not the controller itself. If some aspect of the controller itself must appear, it can be represented as its own distinct sensor or actuator.These are the main design goals:
- Simple devices should be simple to represent, make, and use.
- Simple access and command protocols should be simple to implement.
- Numeric representations should be flexible, yet constrainable.
- As a general rule, one object per distinct variable.
- Complexity should arise from the composition of simple elements arranged in different ways, not from inherent or irreducible complexity.
The principal elements refer to gadgets, gadget-events, listeners, factories, and hubs. Though hubs are often central to an implementation, they rarely appear as significant elements for any purpose other than making new gadgets. For that, they implement a factory interface.Supplemental elements that you can use or not as you choose include groups of gadgets, triggers that look for a condition, actions that can be executed, and loaders that parse text and turn it into gadgets. These elements are useful in many situations, but you may not always need them.
Gadgets, Events, and Listeners
Gadget is the fundamental class. It models an actual or simulated physical device that measures some quantity or condition of interest, or provides settable control over a quantity or state. Each Gadget holds a single integer value and a constraining range for that value. A Gadget also provides access to its value as a normalized float in the range [0.0-1.0]. A Gadget has an optional alarm-range which it can automatically compare to its current value and generate alarm-events when certain conditions are met.A GadgetEvent is sent to a GadgetListener implementation when a Gadget's value changes or when the Gadget detects an alarm condition. The event/listener relationship also provides for customization in the form of a specific method that you can use to extend the meaning of GadgetEvents.
A Range encapsulates a pair of integers representing the upper and lower end-points of an inclusive range. It can examine other integers to determine whether they are within or outside its range, normalize and denormalize to a [0.0-1.0] floating-point range, and force an integer that is outside its range to lie at the appropriate end-point. A Range is used for a Gadget's value-constraining range and for its optional alarm-range.
Gadget Factories and Gadget Info
GadgetFactory is an interface whose factory-methods produce new Gadgets according to supplied arguments that describe the characteristics of a desired Gadget.GadgetInfo is an aggregation of the info that a GadgetFactory needs to create a new Gadget. It also provides methods that can parse and produce String representations that encode the aggregated factory info. These methods are useful for implementing save and load features for particular types of Gadgets.
Gadget Groups and Loaders
A GadgetGroup holds an arbitrary collection of Gadgets. You can add, remove, retrieve, or find Gadgets in the group. You can retrieve the entire group at once, either in an array or by having all its name/Gadget pairs to a Dictionary. You can also apply a GadgetAction (see below) over the entire group.A GadgetLoader processes lines of text into Gadgets, adding them to a GadgetGroup. You define the core parsing methods, while the GadgetLoader takes care of the file or data-stream.
Hubs and Hub I/O Channels
Hub is an abstract class that implements GadgetFactory and also provides a few methods of its own. The most important of those are for getting and setting the Hub's I/O channel. The basic Hub doesn't provide much -- the interesting parts are always in a particular sub-class.HubIO is an interface defining a bi-directional byte-sequenced command and response channel. A Hub always uses a HubIO instance to perform all its I/O for device communication. Communication responsibilities are divided between a Hub and its HubIO so that message-contents production and parsing is in the Hub's realm, and data-transport is in the HubIO's realm. This division simplifies certain things, and allows for such cleverness as replacing a serial-port HubIO with one that uses a TCP/IP Socket instead, and presto you have a networked application (well, there's the small matter of protocols and server, too, but you get the idea).
A few implementations of HubIO are provided, mainly as a diagnostic aid (HexHubIO) and to support a Java-comm SerialPort (SerialHubIO). I also plan to eventually provide a SocketHubIO implementation, at a future time and in conjunction with a corresponding server or servlet component. Feel free to make your own if you don't see a timely enough one from me. Or contract me to write one for you.
Gadget Triggers and Actions
GadgetTrigger is an abstract class that senses some condition and then applies an action to a GadgetGroup previously provided to it. Your sub-class defines what the condition is. GadgetTrigger is a GadgetListener, so you can easily extend it so that certain kinds of GadgetEvents are the triggering condition.GadgetAction is an interface representing an arbitrary action being applied to a single given Gadget. It's used by GadgetTrigger to represent the action precipitated by the detected condition. It's also used by GadgetGroup when it applies an action iteratively to each of its member Gadgets.
All these classes are in the package glguerin.gadgetry.x10.CP290Hub is the Hub, and is the principal class in the package that you will interact with. It makes the Gadgets and is also responsible for all the I/O. It's assisted in handling the I/O by the CP290Comm class, which reads a command-queue and trickles the commands out to the CP290 controller in the proper order. CP290Comm uses a HubIO for its actual I/O, so it should be able to handle that Socket-based HubIO you're just aching to write.
CP290Gadget is the Gadget sub-class. You never instantiate it directly, but always call on a CP290Hub's factory-methods. The Gadget calls on its parent Hub to perform commands, and the Hub calls on its child Gadgets to distribute changes as GadgetEvents.
X10GadgetInfo is a GadgetInfo sub-class that parses and produces device-ID Strings in the typical form of house-code (letters A-P) and unit-codes (numbers 1-16). It also distinguishes lamp modules from appliance modules, and holds a user-visible text-name.
The static classes CP290 and X10 are collections of named constants and static utility methods. See the API docs for details.
Schedules are built on two concepts -- a cyclic or circular clock, and a point in the cycle where some action is scheduled. A cyclic clock means that there is a cycle of some desired length, such as a day, a week, or a year. When the clock reaches the end of the cycle, it recycles back to the beginning, possibly advancing an internal representation of the cycle's starting point in linear time. For example, a daily cyclic-clock will recycle each day, but can still be internally aware of the date, month, and year. These values are not expressed in the cyclic-time though.The other aspect of a cyclic clock is its granularity or tick-interval, for example, by seconds, minutes, or hours. These two values, cycle-length and tick-interval, determine how events are scheduled. You can set a scheduled time at any point in a cycle, but only to the granularity of the tick-interval. For example, a one-day cycle with a one-minute tick interval cannot schedule any action with better than one minute of precision. As scheduled times in the cycle arrive, the actions associated with those times are executed. When the cycle repeats, the scheduled actions are executed again. This is the whole purpose of having a cyclic clock coupled to a recurring schedule of actions.
The scheduling classes live in three related packages:
- glguerin.gadgetry.cyclic contains the abstract base-classes, interfaces, etc. on which any cyclic-time Gadget or Hub can be built. These classes are Locale-aware and are easy to sub-class for supporting localized customs or interpretations.
- glguerin.gadgetry.cyclic.week contains classes for a cycle-length of one week, with a tick-interval of one minute. These classes also provide a daily-cycle option with one minute resolution. The classes are Locale-aware, and sensitive to the local custom for first-day-of-week, day-name abbreviations, and time-formats.
- glguerin.gadgetry.trigger contains classes for parsing and decoding text, producing sensing-Gadgets, GadgetTriggers, GadgetActions, and so on. The MinuteOfWeek classes provide the basic schedule-making capability, but you can easily refer to your own classes, too.
Package glguerin.gadgetry.awt
There are several AWT Components you can use to manipulate and observe Gadgets. These are immediately useful for testing and simple AWT-based utilities. They can also serve as examples for other Components, or as examples for Swing components.
- GadgetList is a List sub-class that maintains an internal GadgetGroup, and presents the items in that group as List-items. It provides methods to add Gadgets, retrieve Gadgets by index or identity, remove Gadgets, and retrieve arrays of Gadgets representing the entire contents or only the selected Gadgets.
- GadgetListFormat is a small class that determines how a GadgetList displays a Gadget in the text of a List-item. Sub-classes for a few typical formats are also provided.
- GadgetSetter is a Panel sub-class that can load, manipulate, and observe any number of Gadgets produced by a single Hub. It presents the Gadgets in a multi-selectable List, so you can send the same command to many Gadgets at once with only a few clicks. The action-buttons allow you to turn Gadgets off and on, set their values to any of 3 configurable preset levels, and increase or decrease the values incrementally. The GadgetSetter listens for GadgetEvents and keeps the display up to date for both value-changes and alarms. GadgetSetter can also load a set of Gadget descriptions from a text file, using a GadgetLoader for parsing.
- GadgetTriggerPanel is a Panel sub-class similar to GadgetSetter, but specialized for Gadgets that represent a sensable condition and send ALARM events to GadgetTriggers. It contains a GadgetList loaded by a TriggerLoader. It also contains buttons to display a trigger-Gadget's information and listeners, to perform the action without triggering the Gadget, and to refresh the display.
- GadgetWatcher is a Panel sub-class that only watches Gadgets, with no capability to set their value. It can work with multiple Gadgets from any number of factories or Hubs, which is more flexible than GadgetSetter.
- HubIOChooser is a Panel sub-class that can dynamically choose and assign a HubIO to a Hub, allowing you to more easily observe the operation of the Hub, and to test new HubIO implementations. It presents HubOptions to choose from, and assigns a HubIO made from a chosen HubOption.
- GadgetSetterFrame, GadgetTriggerFrame, and GadgetWatcherFrame are all principal-frames of simple or test applications. They can be used as-is or as examples.
Package glguerin.gadgetry.util
- ActionAdds, ActionSets, ActionToggles, FakeAlarmAction, and GadgetSpy are widely reusable GadgetActions.
- FactoryGadgetLoader is a GadgetLoader that uses the parser in a GadgetInfo. It gets the GadgetInfo from a GadgetFactory rather than having you specify a particular GadgetInfo.
- StubGadget and StubHub are simple test-oriented stubs.
- TriggerOnAlarm and TriggerOnChanged are widely reusable GadgetTriggers.
- WatchGadget is an abstract Hub-less Gadget that uses a periodic thread to keep watch on some value or quantity. You sub-class it to define what to watch, and the rate of update. This class makes it easy to turn an inactive variable of some kind into an active event-sending Gadget.
X-10 Control and Schedules
There are two applications that can drive a CP290 interface for X-10 control. One is purely a user-interactive direct-control utility, while the other adds scheduling capabilities. Both programs are found in the package app.x10toy.The BathtubToy class is the direct-control utility. It presents a list of Gadgets, which it reads from a text file, and allows you to directly control them. You can also choose the I/O-channel over which CP290 commands and responses are exchanged. Since one of the options is "Serial Port", and the serial-ports themselves are enumerated for each platform, you can select the serial-port that connects to your CP290 device.
The ScheduleToy class is the scheduled-action improvement to the BathtubToy. It provides all the direct-control features, the file-reading feature, and the ability to choose a serial-port, though with a slightly differeny visual layout. It then adds a list of trigger-Gadgets, loaded from a text-file, representing scheduled times at which actions will occur. The scheduled times can mix both daily-cycle and weekly-cycle in the same file. Day-names are localized by default, but an English-only factory can also be designated. The schedule-time, list of target Gadgets (i.e. X-10 modules), and action to take are all given as lines in a text file.
Both BathtubToy and ScheduleToy can fill their lists from arbitrary text files. Under MRJ on Mac OS, the applications support drag-n-drop of files onto their Finder icons. The ScheduleToy distinguishes X-10 Gadget-list files from schedule files using the file-suffix (not Mac-like, but you can change it).
Both classes also use console-out for displaying some text. This is very unsophisticated, and not acceptable for a Real Product -- but these are simple-minded demos, not finished products.
More details on each program's behavior, text-file format, etc. can be found in HTML files supplied with the Gadget-Kit.
A Simple Watcher
This program is found in the package app.watcher.
- The X-10 Inc. web-site often has daily specials on bundles of modules, controllers, remotes, etc.
- The SmartHome Web Site sells X-10 modules, controllers, and many non-X10 devices for home automation, home theatre, alarm systems, etc.
- The CP290 Programming Manual in PDF format.
- The CM11A Serial Protocol in text format.
- The Home Automation FAQ page.
- Some of the microcontrollers I use are flash-programmable Atmel 8051-based chips -- inexpensive, versatile, with a range of features.
To Greg's Home Page
To Greg's Software Page