#!/usr/bin/env ruby # # huec - Philips (friends of) hue command-line utility # # Hued is Copyright © 2011 Paul van Tilburg # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. require "hued/version" require "huey" require "logger" require "optparse" require "pp" require "pry" require "rainbow" include Huey def msg(str="") puts(str) if @interactive end def status_line(blb) mode = [] if blb.reachable on_off = blb.on ? Rainbow("on").bright.green : Rainbow("off").red case blb.colormode when "xy" mode << "xy: #{blb.xy.inspect}" when "hs" mode << "hue: #{blb.hue}" << "sat: #{blb.sat}" when "ct" mode << "ct: #{blb.ct}" end mode << "bri: #{blb.bri}" else on_off = Rainbow("unreachable").bright.red end line = "%2d: %-30s (%-12s" % [blb.id, blb.name, on_off, mode] if mode.empty? line += ")" else line += ", #{mode.join(', ')})" end return line end def prompt_status reload_needed = Time.now - @prompt_stamp > 10 prompt_str = Huey::Bulb.all.map do |blb| blb.reload if reload_needed if blb.reachable blb.on ? Rainbow("o").bright.green : Rainbow("o").red else Rainbow("x").bright.red end end.join @prompt_stamp = Time.now if reload_needed prompt_str end def lights Huey::Bulb.all.each do |blb| msg status_line(blb) end true end def groups Huey::Group.all.each do |grp| msg "%2d: %s (%s)" % [grp.id, grp.name, grp.bulbs.map(&:id).join(', ')] end true end def events events_cfg = File.join(@options[:config_dir], "events.yml") Huey::Event.import(events_cfg).each_with_index do |ev, idx| msg "%2d: %s" % [idx, ev.name] end true end def scenes @scenes = {} scenes_cfg = File.join(@options[:config_dir], "scenes.yml") YAML.load_file(scenes_cfg).each_with_index do |(name, entry), idx| msg "%2d: %s" % [idx, name] @scenes[name] = entry.map do |ev_options| # Keys should be symbols options = ev_options.inject({}) { |opts, (k, v)| opts[k.to_sym] = v; opts } event = Huey::Event.new(options) event.actions["on"] = true if event.actions["on"].nil? event end end true end def refresh! Huey::Bulb.all.each do |blb| blb.reload msg status_line(blb) end true end def get(*names_or_ids) names_or_ids.map do |name_or_id| blb = Huey::Bulb.find(name_or_id) msg status_line(blb) true end end def set(*names_or_ids, opts) blb = nil names_or_ids.map do |name_or_id| blb = Huey::Bulb.find(name_or_id) blb.update(opts) end rescue Huey::Errors::BulbOff blb.update(on: true) retry rescue Huey::Errors::Error => e msg "Error: #{e.message}" end def getgrp(*names_or_ids) names_or_ids.map do |name_or_id| Huey::Group.find(name_or_id).each do |blb| msg status_line(blb) end true end end def setgrp(*names_or_ids, opts) names_or_ids.map do |name_or_id| grp = Huey::Group.find(name_or_id) grp.update(opts) end end def event(name_or_id) ev = case name_or_id when Fixnum Huey::Event.all[name_or_id] when String Huey::Event.find(name_or_id) end ev.execute end def scene(name_or_id) sc = case name_or_id when Fixnum @scenes.values[name_or_id] when String @scenes[name_or_id] end sc.map { |ev| ev.execute } end def alert(*names_or_ids) names_or_ids.map do |name_or_id| blb = Huey::Bulb.find(name_or_id) blb.alert! end end def off(*names_or_ids) set(*names_or_ids, on: false) end def on(*names_or_ids) set(*names_or_ids, on: true) end def commands msg < "config"} opt_parser = OptionParser.new do |opts| opts.banner = "Usage: huec [options]" opts.separator "" opts.on("-c", "--config-dir [CONFDIR] ", "set an alternative configuration directory") do |cd| @options[:config_dir] = cd end opts.on("--hue-debug", "log hue bridge communication output") do @options[:hue_debug] = true end opts.on_tail("-h", "--help", "show this help message") do puts opts exit end opts.on_tail("-v", "--version", "show version") do puts "Hued version #{Hued::VERSION}" exit end end begin opt_parser.parse! rescue OptionParser::InvalidOption => e warn e.message abort opt_parser.to_s end @interactive = ARGV.empty? msg "Starting huec #{Hued::VERSION}..." bridge_cfg = YAML.load_file(File.join(@options[:config_dir], "bridge.yml")) Huey.configure do |cfg| cfg.hue_ip = bridge_cfg["ip"] cfg.uuid = bridge_cfg["user"] end Huey.logger.level = @options[:hue_debug] ? Logger::DEBUG : Logger::FATAL msg "Configured bridge connection" msg "Discovering lights..." lights msg msg "Discovering groups..." groups msg msg "Loading events..." events msg msg "Loading scenes..." scenes msg msg "Loading sensors..." sensors msg msg "All done!" msg "Use 'commands' to see a list of additional commands to pry's." msg @prompt_stamp = Time.now if @interactive Pry.config.prompt = proc { "#{prompt_status}> " } binding.pry(quiet: true) else eval ARGV.join(" ") end