#!/usr/bin/env ruby module X10 module Cm17a # A CM17A device that responds to on/off and adjust (brightness) # commands. # # Typical use: # # lamp = X10.device("a2") # Create the device # lamp.on # Turn the lamp on # lamp.adjust(-0.5) # Dim the lamp # lamp.off # Turn the lamp off # class Device attr_reader :address, :controller # Create a new X10 device using a CM17A protocol controller. # Such a device can handle on/off commands and simple dim # controls. # # Normally device objects are created through the X10 framework # and not directly by the client software. def initialize(house, unit, controller) @house = house @unit = unit @controller = controller @address = X10.make_address(house, unit) end # Turn the device on. def on @controller.command(@house, @unit, X10::Cm17a::ON, 0) @level = 1.0 if @on == false @on = true end # Turn the device off. def off @controller.command(@house, @unit, X10::Cm17a::OFF, 0) @level = 0.0 @on = false end # Adjust the brightness level. # # The level adjustment is given as a number between 0 and 1. An # adjustment amount of 1 will adjust a completely dim device # into a completely bright device. An adjustment of 0.5 will be # one half of full range. # # Negative adjustment amounts dim the device. Positive # adjustments brighten the device. def adjust(amount) steps = steps_for(amount) while steps > 0 step = (steps > 6 ? 6 : steps) if amount > 0 brighten(step) else dim(step) end steps -= step end if @level @level += amount @level = 0.0 if @level < 0 @level = 1.0 if @level > 1 end end private # -- Questionable Methods -------------------------------------- # The following methods are provided as private methods. They # are used in testing, but I am uncertain whether they should be # part of the public interface, due to the uncertaintity of # there implementation. # Is the device on? # # Since the CM17A protocol is write only, we can't really sense # the on/off state of the device, so we remember the last # commanded state. This approach has the following # disadvantages: # # * The on/off state is indeterminate until the first command is # issued. Asking for the on/off state before the first # command will throw an X10::X10Error exception. # * If there is more than one device object controlling a single # physical device, then the on/off state can be invalidated by # second device object. def on? fail X10::X10Error, "On/Off state is unknown" if @on.nil? @on end # Is the device off? # # See also the discussion in the on? method. def off? ! on? end # Return the current brightness level between 0 (very dim) and # 1.0 (very bright) of the device. # # Again, since the CM17A protocol is write only, the same # caveats that apply to on? and off? are also applicable here. # # Furthermore, the real brightness level is a mystery. The # protocol docs say that stepping the brighteness level changes # it by approximately 5%. However, there seems to be only 10 or # so steps from completely dim to completely bright. def level fail X10::X10Error, "Level is unknown" if @level.nil? @level end # -- Helper Commands ------------------------------------------- # Brightness steps for the given amount. def steps_for(amount) (amount * 10).round.abs end # Send a dim command for the given number of steps. def dim(steps) @controller.command(@house, @unit, X10::Cm17a::DIM, steps) end # Send a brighten command for the given number of steps. def brighten(steps) @controller.command(@house, @unit, X10::Cm17a::BRIGHTEN, steps) end end end end