The Nook system is a custom home automation system that allows the control of multiple devices (such as lights) through a range of inputs (such as keypads and a smartwatch). The design is based on the use of general-purpose scripting to allow the system to be fully controlled in any reasonably expressible way.
The Nook system consists of a number of components that can be assembled into a complete system:
- Smart lights: Tasmota, LIFX, Tuya-derived, Raspberry Pi LEDs via server.
- Inputs: Keyboard, keypads, joypads.
- Outputs: Remote LEDs, character LCD.
- Interactive devices: Browser, smartwatch, phone, remote graphical terminal.
- Active components: RM4 IR transmitter, smart power switches.
- Sensors: RM4 Temperature/humidity.
- Time: Real, or simulated with adjustable time and rate (eg. slowed/accelerated).
Each component generally also has a simulated counterpart. The full set of components can be assembled into a complete system dynamically at runtime, allowing any mix of real and simulated components to be used. This is useful for testing a range of scenarios and individually singling out real components during development to test and diagnose issues.
The Nook system provides server functionality in multiple forms, including:
- Browser interface (input plus status display)
- Input devices (eg. controllers)
- Interactive devices (eg. smartwatch, phone)
- Connection via a remote terminal
The core operation of the system is managed directly by a general-purpose Ruby script called multiple times per second. Based on the current time and state of the system, inputs, modes, settings, and overrides, a decision is made about the state of outputs to set and control. Changes resulting from these decisions are sent out to the rest of the system.
This decision to control the system with a general-purpose script was an original design goal. Many home automation systems provide a framework that allow you to express relatively simple automation and control tasks easily. This allows you to get started quickly. However, should you move beyond simpler configurations, they often scale badly and impose considerable restrictions on what you can do. I wanted to be able to adjust the state of anything based on any criteria whatsoever, manually and automatically, without restriction. Doing this required using a general-purpose scripting language rather than a framework. As a software engineer, expressing things in this way was a much more natural choice for me.
Input devices generally maintain a connection to the server and send updates based on changes (eg. keypresses, or button presses), but can work in the reverse direction (eg. the server connects out to the device). A script manages received inputs and events, and based on a central configuration, converts it to virtual inputs that then lead to actions, or makes direct changes to the state of the system on receipt. Inputs can also be configured as modifiers (similar to say the Shift key on a keyboard), allowing a greater number of actions to be controlled with the same number of inputs.
Originally inputs were smarter devices, with the device deciding what action should be taken on an input change, and sending that as a request to the server. For example: A button might control a specific light, so the input would send a request to change that light. Whilst this allows more powerful device-specific configuration, this meant configuration was needed on each device to manage how that device worked and what it did, which was nightmarish to maintain with multiple devices. This logic was later shifted to the server, with inputs being simple devices that just report changes (eg. when a button is pressed). All of the complexity is shifted to the server. This means all configuration can be managed in one place, where common actions across devices can be better organized, which is considerably easier.
A significant part of the system is light automation, such as adjusting lighting based on conditions and time of day. For that reason, having simulated time with an adjustable time and rate is important. One such example of the benefit of simulated time is as follows: An evening's worth of automatic lighting adjustment could be tested in the middle of the day at 20x the normal rate, to observe how it would behave when adjusting evening lighting across a longer time.
For most components I have written a dedicated driver. For other components, the system runs alongside an existing home automation system (Home Assistant), connecting to a minimal installation, and using the drivers built into that. In such cases a minimal driver talks to that server, and controls the device indirectly through that.
The IR transmitter in the RM4 is used to control a network of several HDMI switch and matrix devices to reconfigure the connections between multiple devices and multiple displays. The RM4 broadcasts IR codes across all devices, and each device interprets input it understands. There are overlaps in the codes used by the various devices, timing issues, and some devices misbehave with invalid codes. For each desired combination, a working sequence of codes has been discovered and is broadcast that will result in the desired configuration being reached. Using the Nook system, instead of configuring multiple devices by hand, a single keypress on a nearby keypad will reconfigure each of the devices to a given overall configuration. This allows multiple monitor configurations to be selected with a single keypress.
A watch (wristwatch) is used to view the system state and control the system. This is a powerful part of the system and allows it to be controlled from any place the watch can be worn. Click here to learn more.
This is a quick writeup of the current capability of the system. There is much more to add, and the system is continually evolving. I hope to add more to this writeup as the opportunity presents itself. :)