Class: NLHue::Bridge
- Inherits:
-
Object
- Object
- NLHue::Bridge
- Extended by:
- Log
- Includes:
- Log
- Defined in:
- lib/nlhue/bridge.rb
Overview
A class representing a Hue bridge. A Bridge object may not refer to an actual Hue bridge if verify() hasn’t succeeded. Manages a list of lights and groups on the bridge. HTTP requests to the bridge are queued and sent one at a time to prevent overloading the bridge’s CPU.
Constant Summary collapse
- RATE_LIMIT =
Seconds to wait after an update round finishes before sending more updates to lights and groups.
0.2- @@bridge_cbs =
callbacks notified when a bridge has its first successful update
[]
Instance Attribute Summary collapse
-
#addr ⇒ Object
Returns the value of attribute addr.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#serial ⇒ Object
readonly
Returns the value of attribute serial.
-
#username ⇒ Object
Returns the value of attribute username.
-
#whitelist ⇒ Object
readonly
Returns the value of attribute whitelist.
Class Method Summary collapse
-
.add_bridge_callback(&block) ⇒ Object
Adds a callback to be called with a Bridge object and a status each time a Bridge has its first successful update, adds or removes lights or groups, or becomes unregistered.
-
.notify_bridge_callbacks(br, status) ⇒ Object
Sends the given bridge to all attached first update callbacks.
-
.remove_bridge_callback(cb) ⇒ Object
Removes the given callback (returned by add_bridge_callback) from Bridge first update/unregistration notifications.
Instance Method Summary collapse
-
#add_target(t, &block) ⇒ Object
Schedules a Light, Scene, or Group to have its deferred values sent the next time the rate limiting timer fires, or immediately if the rate limiting timer has expired.
-
#add_update_callback(&cb) ⇒ Object
Adds a callback to be notified when a subscription update is received, or when a subscription update fails.
-
#check_json(response) ⇒ Object
Checks for a valid JSON-containing response from an HTTP request method, returns an error if invalid or no response.
-
#check_username(username) ⇒ Object
Throws errors if the given username is invalid (may not catch all invalid names).
-
#clean ⇒ Object
Unsubscribes from bridge updates, marks this bridge as unregistered, notifies global bridge callbacks added with add_bridge_callback, then removes references to configuration, lights, groups, and update callbacks.
-
#create_group(name, lights, &block) ⇒ Object
Creates a new group with the given name and list of lights.
-
#delete_api(subpath, category = nil, &block) ⇒ Object
Makes a DELETE request under the API using this Bridge’s stored username.
-
#delete_group(group, &block) ⇒ Object
Deletes the given NLHue::Group on this bridge.
-
#delete_scene(scene, &block) ⇒ Object
Deletes the given NLHue::Scene on this bridge.
-
#find_scene(prefix) ⇒ Object
Returns the scene with an exactly matching ID, the most recently created Scene with a name starting with
prefix(that is, the scene occurring last in an alphanumeric sort), or nil if no match was found. -
#get_api(subpath, category = nil, &block) ⇒ Object
Makes a GET request under the API using this Bridge’s stored username.
-
#groups ⇒ Object
Returns a Hash mapping group IDs to Group objects representing the groups known to this bridge, including the default group 0 that contains all lights from this bridge.
-
#initialize(addr, serial = nil) ⇒ Bridge
constructor
addr - The IP address or hostname of the Hue bridge.
-
#lights ⇒ Object
Returns a Hash mapping light IDs to Light objects, representing the lights known to the Hue bridge.
-
#num_groups ⇒ Object
The number of groups known to this bridge, including the default group that contains all lights known to the bridge.
-
#num_lights ⇒ Object
The number of lights known to this bridge.
-
#num_scenes ⇒ Object
The number of scenes found on the bridge.
-
#post_api(subpath, data, category = nil, content_type = nil, &block) ⇒ Object
Makes a POST request under the API using this Bridge’s stored username.
-
#put_api(subpath, data, category = nil, content_type = nil, &block) ⇒ Object
Makes a PUT request under the API using this Bridge’s stored username.
-
#register(devicetype, &block) ⇒ Object
Attempts to register with the Bridge.
-
#registered? ⇒ Boolean
Returns whether the Bridge object believes it is registered with its associated Hue bridge.
-
#remove_update_callback(cb) ⇒ Object
Removes the given callback (returned by add_update_callback) from the list of callbacks notified with subscription events.
-
#scan_active? ⇒ Boolean
Returns true if a scan for lights is active (as of the last call to #update), false otherwise.
-
#scan_lights(&block) ⇒ Object
Initiates a scan for new lights.
-
#scan_status(request = false, &block) ⇒ Object
Calls the given block (if given) with true and the last known light scan status from the bridge.
-
#scenes ⇒ Object
Returns a Hash mapping scene IDs to Scene objects.
-
#subscribe(interval = 1) ⇒ Object
Starts a timer that retrieves the current state of the bridge every interval seconds.
-
#subscribed? ⇒ Boolean
Returns true if this bridge is subscribed (i.e. periodically polling the Hue bridge for updates).
-
#to_h(include_config = false) ⇒ Object
Returns a Hash with information about this bridge: { :addr => “[IP address]”, :name => “[name]”, :serial => “[serial number]”, :registered => true/false, :scan => [return value of #scan_status], :lights => [hash containing Light objects (see #lights)], :groups => [hash containing Group objects (see #groups)], :scenes => [hash containing Scene objects (see #scenes)], :config => [raw config from bridge] if include_config }.
-
#to_json(*args) ⇒ Object
Return value of to_h converted to a JSON string.
-
#to_s ⇒ Object
“Hue Bridge: [IP]: [Friendly Name] ([serial]) - N lights”.
-
#unregister(username = nil, &block) ⇒ Object
Deletes the given
username(or this Bridge object’s current username ifusernameis nil) from the Bridge’s whitelist, sets this Bridge’s username to nil, and sets its registered state to false. -
#unsubscribe ⇒ Object
Stops the timer started by subscribe(), if one is running.
-
#update(&block) ⇒ Object
Updates the Bridge object with the lights, groups, and config of the Hue bridge.
-
#updated? ⇒ Boolean
Returns whether the Bridge object has had at least one successful update from #update.
-
#verified? ⇒ Boolean
Indicates whether verification succeeded.
-
#verify(&block) ⇒ Object
Calls the given block with true or false if verification by description.xml succeeds or fails.
Methods included from Log
bench, log, log_e, on_bench, on_log, on_log_e
Constructor Details
#initialize(addr, serial = nil) ⇒ Bridge
addr - The IP address or hostname of the Hue bridge. serial - The serial number of the bridge, if available (parsed from the USN header in a UPnP response)
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/nlhue/bridge.rb', line 89 def initialize addr, serial = nil @addr = addr @verified = false @username = nil @name = nil @config = nil @registered = false @lights = {} @groups = {} @scenes = {} @whitelist = {} @lightscan = {'lastscan' => 'none'} if serial && serial =~ /^[0-9A-Fa-f]{12}$/ @serial = serial.downcase else @serial = nil end @request_queue = NLHue::RequestQueue.new addr, 2 @update_timer = nil @update_callbacks = [] @rate_timer = nil @rate_targets = {} @rate_proc = proc do if @rate_targets.empty? log "No targets, canceling rate timer." # XXX @rate_timer.cancel if @rate_timer @rate_timer = nil else log "Sending targets from rate timer." # XXX send_targets do @rate_timer = EM::Timer.new(RATE_LIMIT, @rate_proc) end end end end |
Instance Attribute Details
#addr ⇒ Object
Returns the value of attribute addr.
44 45 46 |
# File 'lib/nlhue/bridge.rb', line 44 def addr @addr end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
44 45 46 |
# File 'lib/nlhue/bridge.rb', line 44 def name @name end |
#serial ⇒ Object (readonly)
Returns the value of attribute serial.
44 45 46 |
# File 'lib/nlhue/bridge.rb', line 44 def serial @serial end |
#username ⇒ Object
Returns the value of attribute username.
44 45 46 |
# File 'lib/nlhue/bridge.rb', line 44 def username @username end |
#whitelist ⇒ Object (readonly)
Returns the value of attribute whitelist.
44 45 46 |
# File 'lib/nlhue/bridge.rb', line 44 def whitelist @whitelist end |
Class Method Details
.add_bridge_callback(&block) ⇒ Object
Adds a callback to be called with a Bridge object and a status each time a Bridge has its first successful update, adds or removes lights or groups, or becomes unregistered. Bridge callbacks will be called after any corresponding :add or :del disco event is delivered. Returns a Proc object that may be passed to remove_update_cb.
Callback parameters: Bridge first update: [Bridge], true
Bridge added/removed lights or groups: [Bridge], true
Bridge unregistered: [Bridge], false
64 65 66 67 |
# File 'lib/nlhue/bridge.rb', line 64 def self.add_bridge_callback &block @@bridge_cbs << block block end |
.notify_bridge_callbacks(br, status) ⇒ Object
Sends the given bridge to all attached first update callbacks.
76 77 78 79 80 81 82 83 84 |
# File 'lib/nlhue/bridge.rb', line 76 def self.notify_bridge_callbacks br, status @@bridge_cbs.each do |cb| begin cb.call br, status rescue => e log_e e, "Error calling a first update callback" end end end |
.remove_bridge_callback(cb) ⇒ Object
Removes the given callback (returned by add_bridge_callback) from Bridge first update/unregistration notifications.
71 72 73 |
# File 'lib/nlhue/bridge.rb', line 71 def self.remove_bridge_callback cb @@bridge_cbs.delete cb end |
Instance Method Details
#add_target(t, &block) ⇒ Object
Schedules a Light, Scene, or Group to have its deferred values sent the next time the rate limiting timer fires, or immediately if the rate limiting timer has expired. Starts the rate limiting timer if it is not running.
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/nlhue/bridge.rb', line 773 def add_target t, &block raise 'Target must respond to :send_changes' unless t.respond_to?(:send_changes) raise "Target is from #{t.bridge.serial} not this bridge (#{@serial})" unless t.bridge == self log "Adding deferred target #{t}" # XXX @rate_targets[t] ||= [] @rate_targets[t] << block if block_given? # TODO: Use different timers for different request types unless @rate_timer log "No rate timer -- sending targets on next tick" # XXX # Waiting until the next tick allows multiple # updates to be queued in the current tick that # will all go out at the same time. EM.next_tick do log "It's next tick -- sending targets now" # XXX send_targets end log "Setting rate timer" @rate_timer = EM::Timer.new(RATE_LIMIT, @rate_proc) else log "Rate timer is set -- not sending targets now" # XXX end end |
#add_update_callback(&cb) ⇒ Object
Adds a callback to be notified when a subscription update is received, or when a subscription update fails. The return value may be passed to remove_update_callback.
Callback parameters: Update successful: true, [lights or groups changed: true/false]
Update failed: false, [exception]
257 258 259 260 |
# File 'lib/nlhue/bridge.rb', line 257 def add_update_callback &cb @update_callbacks << cb cb end |
#check_json(response) ⇒ Object
Checks for a valid JSON-containing response from an HTTP request method, returns an error if invalid or no response. Does not consider non-200 HTTP response codes as errors. Returns true and the received JSON if no error occurred, or false and an exception if an error did occur. Marks this bridge as not registered if there is a NotRegisteredError.
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 |
# File 'lib/nlhue/bridge.rb', line 660 def check_json response status = false result = nil begin raise 'No response received.' if response == false if response.is_a?(Hash) status = true result_msgs = [] result = JSON.parse response[:content] if result.is_a? Array result.each do |v| if v.is_a?(Hash) && v['error'].is_a?(Hash); then status = false result_msgs << v['error']['description'] end end end unless status if result_msgs.include?('link button not pressed') raise LinkButtonError.new elsif result_msgs.include?('unauthorized user') was_reg = @registered @registered = false Bridge.notify_bridge_callbacks self, false if was_reg raise NotRegisteredError.new else raise StandardError.new(result_msgs.join(', ')) end end end rescue => e status = false result = e end return status, result end |
#check_username(username) ⇒ Object
Throws errors if the given username is invalid (may not catch all invalid names).
648 649 650 651 652 |
# File 'lib/nlhue/bridge.rb', line 648 def check_username username raise 'Username must be a String' unless username.is_a?(String) raise 'Username must be >= 10 characters.' unless username.to_s.length >= 10 raise 'Spaces are not permitted in usernames.' if username =~ /[[:space:]]/ end |
#clean ⇒ Object
Unsubscribes from bridge updates, marks this bridge as unregistered, notifies global bridge callbacks added with add_bridge_callback, then removes references to configuration, lights, groups, and update callbacks.
632 633 634 635 636 637 638 639 640 641 642 643 644 |
# File 'lib/nlhue/bridge.rb', line 632 def clean was_updated = updated? unsubscribe @registered = false Bridge.notify_bridge_callbacks self, false if was_updated @verified = false @config = nil @lights.clear @groups.clear @update_callbacks.clear end |
#create_group(name, lights, &block) ⇒ Object
Creates a new group with the given name and list of lights. The given block will be called with true and a NLHue::Group object on success, false and an error on failure. If group creation succeeds, all bridge callbacks added with Bridge.add_bridge_callback will be notified after the new group is yielded to the block (if a block is given). Note that the group’s name may be changed by the bridge.
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 |
# File 'lib/nlhue/bridge.rb', line 519 def create_group name, lights, &block raise "No group name was given" unless name.is_a?(String) && name.length > 0 raise "No lights were given" unless lights.is_a?(Array) && lights.length > 0 light_ids = [] lights.each do |l| raise "All given lights must be NLHue::Light objects" unless l.is_a?(Light) raise "Light #{l.id} (#{l.name}) is not from this bridge." if l.bridge != self light_ids << l.id.to_s end group_data = { :lights => light_ids, :name => name }.to_json post_api '/groups', group_data, :lights do |response| status, result = check_json response begin result = result.first if result.is_a? Array if status && result['success'] id = result['success']['id'].split('/').last.to_i raise "Invalid ID received for new group: '#{result['success']['id']}'" unless id > 0 group = Group.new(self, id, { 'name' => name, 'lights' => light_ids, 'action' => {} }) group.update do |upstatus, upresult| if upstatus @groups[id] = group Bridge.notify_bridge_callbacks self, true yield true, group if block_given? else yield upstatus, upresult if block_given? end end else raise result end rescue => e yield false, e if block_given? end end end |
#delete_api(subpath, category = nil, &block) ⇒ Object
Makes a DELETE request under the API using this Bridge’s stored username.
765 766 767 |
# File 'lib/nlhue/bridge.rb', line 765 def delete_api subpath, category=nil, &block @request_queue.delete "/api/#{api_key}#{subpath}", category, &block end |
#delete_group(group, &block) ⇒ Object
Deletes the given NLHue::Group on this bridge. Raises an exception if the group is group 0. Calls the given block with true and a message on success, or false and an error on failure. Bridge notification callbacks will be called after the result is yielded.
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 |
# File 'lib/nlhue/bridge.rb', line 590 def delete_group group, &block raise "No group was given to delete" if group.nil? raise "Group must be a NLHue::Group object" unless group.is_a?(Group) raise "Group is not from this bridge" unless group.bridge == self raise "Cannot delete group 0" if group.id == 0 delete_api "/groups/#{group.id}", :lights do |response| status, result = check_json response if status @groups.delete group.id end yield status, result if block_given? if status Bridge.notify_bridge_callbacks self, true end end end |
#delete_scene(scene, &block) ⇒ Object
Deletes the given NLHue::Scene on this bridge. Calls the given block with true and a message on success, or false and an error on failure. Bridge notification callbacks will be called after the result is yielded.
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/nlhue/bridge.rb', line 565 def delete_scene scene, &block raise "No scene was given to delete" if scene.nil? raise "Scene must be a NLHue::Scene object" unless scene.is_a?(Scene) raise "Scene is not from this bridge" unless scene.bridge == self delete_api "/scenes/#{CGI.escape(scene.id)}", :lights do |response| status, result = check_json response if status @scenes.delete scene.id end yield status, result if block_given? if status Bridge.notify_bridge_callbacks self, true end end end |
#find_scene(prefix) ⇒ Object
Returns the scene with an exactly matching ID, the most recently created Scene with a name starting with prefix (that is, the scene occurring last in an alphanumeric sort), or nil if no match was found.
501 502 503 504 505 506 507 508 509 510 |
# File 'lib/nlhue/bridge.rb', line 501 def find_scene(prefix) return @scenes[prefix] if @scenes.include? prefix prefix = prefix.downcase @scenes.select{|id, scene| scene.name.downcase.start_with?(prefix) }.values.max_by{|s| s.name } end |
#get_api(subpath, category = nil, &block) ⇒ Object
Makes a GET request under the API using this Bridge’s stored username.
747 748 749 |
# File 'lib/nlhue/bridge.rb', line 747 def get_api subpath, category=nil, &block @request_queue.get "/api/#{api_key}#{subpath}", &block end |
#groups ⇒ Object
Returns a Hash mapping group IDs to Group objects representing the groups known to this bridge, including the default group 0 that contains all lights from this bridge.
476 477 478 |
# File 'lib/nlhue/bridge.rb', line 476 def groups @groups.clone end |
#lights ⇒ Object
Returns a Hash mapping light IDs to Light objects, representing the lights known to the Hue bridge.
464 465 466 |
# File 'lib/nlhue/bridge.rb', line 464 def lights @lights.clone end |
#num_groups ⇒ Object
The number of groups known to this bridge, including the default group that contains all lights known to the bridge.
482 483 484 |
# File 'lib/nlhue/bridge.rb', line 482 def num_groups @groups.length end |
#num_lights ⇒ Object
The number of lights known to this bridge.
469 470 471 |
# File 'lib/nlhue/bridge.rb', line 469 def num_lights @lights.length end |
#num_scenes ⇒ Object
The number of scenes found on the bridge.
493 494 495 |
# File 'lib/nlhue/bridge.rb', line 493 def num_scenes @scenes.length end |
#post_api(subpath, data, category = nil, content_type = nil, &block) ⇒ Object
Makes a POST request under the API using this Bridge’s stored username.
753 754 755 |
# File 'lib/nlhue/bridge.rb', line 753 def post_api subpath, data, category=nil, content_type=nil, &block @request_queue.post "/api/#{api_key}#{subpath}", data, category, content_type, &block end |
#put_api(subpath, data, category = nil, content_type = nil, &block) ⇒ Object
Makes a PUT request under the API using this Bridge’s stored username.
759 760 761 |
# File 'lib/nlhue/bridge.rb', line 759 def put_api subpath, data, category=nil, content_type=nil, &block @request_queue.put "/api/#{api_key}#{subpath}", data, category, content_type, &block end |
#register(devicetype, &block) ⇒ Object
Attempts to register with the Bridge. The block will be called with true and the result array if registration succeeds, false and an Exception if not. If registration succeeds, the Bridge object’s current username will be set to the username returned by the bridge. If the Bridge is already registered it will not be re-registered, and the block will be called with true and the current username. Call #update after registration succeeds. #registered? will not return true until #update has succeeded.
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/nlhue/bridge.rb', line 184 def register devicetype, &block raise NotVerifiedError.new unless @verified if @username && @registered yield true, @username return end msg = %Q{{"devicetype":#{devicetype.to_json}}} @request_queue.post '/api', msg, :registration, nil, 6 do |response| status, result = check_json response if status @username = result.first['success']['username'] end yield status, result end end |
#registered? ⇒ Boolean
Returns whether the Bridge object believes it is registered with its associated Hue bridge. Set to true when #update or #register succeeds, false if a NotRegisteredError occurs.
458 459 460 |
# File 'lib/nlhue/bridge.rb', line 458 def registered? @registered end |
#remove_update_callback(cb) ⇒ Object
Removes the given callback (returned by add_update_callback) from the list of callbacks notified with subscription events.
264 265 266 |
# File 'lib/nlhue/bridge.rb', line 264 def remove_update_callback cb @update_callbacks.delete cb end |
#scan_active? ⇒ Boolean
Returns true if a scan for lights is active (as of the last call to #update), false otherwise.
431 432 433 |
# File 'lib/nlhue/bridge.rb', line 431 def scan_active? @lightscan['lastscan'] == 'active' end |
#scan_lights(&block) ⇒ Object
Initiates a scan for new lights. If a block is given, yields true if the scan was started, an exception if there was an error.
378 379 380 381 382 383 384 385 386 387 388 |
# File 'lib/nlhue/bridge.rb', line 378 def scan_lights &block post_api '/lights', nil do |response| begin status, result = check_json response @lightscan['lastscan'] = 'active' if status yield status if block_given? rescue => e yield e end end end |
#scan_status(request = false, &block) ⇒ Object
Calls the given block (if given) with true and the last known light scan status from the bridge. Requests the current scan status from the bridge if request is true. The block will be called with false and an exception if an error occurs during a request. Returns the last known scan status.
The scan status is a Hash with the following form: { ‘1’ => { ‘name’ => ‘New Light 1’ }, # If new lights were found ‘2’ => { ‘name’ => ‘New Light 2’ }, ‘lastscan’ => ‘active’/‘none’/ISO8601:2004 }
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/nlhue/bridge.rb', line 402 def scan_status request=false, &block if request get_api '/lights/new' do |response| begin status, result = check_json response if status # Update group 0 if new lights are found or when a scan completes if @lightscan['lastscan'] == 'active' && result['lastscan'] != 'active' puts "Updating group 0" # XXX @groups[0].update end @lightscan = result end yield status, result if block_given? rescue => e yield e end end else yield true, @lightscan if block_given? end @lightscan unless block_given? end |
#scenes ⇒ Object
Returns a Hash mapping scene IDs to Scene objects. Unlike lights and groups, scenes have String IDs.
488 489 490 |
# File 'lib/nlhue/bridge.rb', line 488 def scenes @scenes.clone end |
#subscribe(interval = 1) ⇒ Object
Starts a timer that retrieves the current state of the bridge every interval seconds. Does nothing if this Bridge is already subscribed.
229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/nlhue/bridge.rb', line 229 def subscribe interval=1 return if @update_timer update_proc = proc { update do |status, result| @update_timer = EM::Timer.new(interval, update_proc) if @update_timer end } @update_timer = EM::Timer.new(interval, update_proc) end |
#subscribed? ⇒ Boolean
Returns true if this bridge is subscribed (i.e. periodically polling the Hue bridge for updates).
451 452 453 |
# File 'lib/nlhue/bridge.rb', line 451 def subscribed? !!@update_timer end |
#to_h(include_config = false) ⇒ Object
Returns a Hash with information about this bridge: { :addr => “[IP address]”, :name => “[name]”, :serial => “[serial number]”, :registered => true/false, :scan => [return value of #scan_status], :lights => [hash containing Light objects (see #lights)], :groups => [hash containing Group objects (see #groups)], :scenes => [hash containing Scene objects (see #scenes)], :config => [raw config from bridge] if include_config }
Do not modify the included lights and groups hashes.
724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
# File 'lib/nlhue/bridge.rb', line 724 def to_h include_config=false h = { :addr => @addr, :name => @name, :serial => @serial, :registered => @registered, :scan => @lightscan, :lights => @lights, :groups => @groups, :scenes => @scenes, } h[:config] = @config if include_config h end |
#to_json(*args) ⇒ Object
Return value of to_h converted to a JSON string. Options: :include_config => true – include raw config returned by the bridge
741 742 743 |
# File 'lib/nlhue/bridge.rb', line 741 def to_json *args to_h(args[0].is_a?(Hash) && args[0][:include_config]).to_json(*args) end |
#to_s ⇒ Object
“Hue Bridge: [IP]: [Friendly Name] ([serial]) - N lights”
704 705 706 707 708 |
# File 'lib/nlhue/bridge.rb', line 704 def to_s str = "Hue Bridge: #{@addr}: #{@name} (#{@serial}) - #{@lights.length} lights" str << " (#{registered? ? '' : 'un'}registered)" str end |
#unregister(username = nil, &block) ⇒ Object
Deletes the given username (or this Bridge object’s current username if username is nil) from the Bridge’s whitelist, sets this Bridge’s username to nil, and sets its registered state to false.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/nlhue/bridge.rb', line 208 def unregister username = nil, &block raise NotVerifiedError.new unless @verified username ||= @username @request_queue.delete "/api/#{username}/config/whitelist/#{username}", :registration, 6 do |response| status, result = check_json response if @username == username && status @registered = false @username = nil Bridge.notify_bridge_callbacks self, false end yield status, result end end |
#unsubscribe ⇒ Object
Stops the timer started by subscribe(), if one is running.
242 243 244 245 |
# File 'lib/nlhue/bridge.rb', line 242 def unsubscribe @update_timer.cancel if @update_timer @update_timer = nil end |
#update(&block) ⇒ Object
Updates the Bridge object with the lights, groups, and config of the Hue bridge. Also updates the current light scan status on the first update or if the Bridge thinks a scan is currently active. On success the given block will be called with true and whether the lights/groups were changed, false and an exception on error.
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/nlhue/bridge.rb', line 274 def update &block @request_queue.get "/api/#{api_key}", :info do |response| status, result = check_json response changed = false begin if status first_update = !@registered # TODO: Extract a helper method for adding new # members to and removing old members from a list @config = result @config['lights'].each do |id, info| id = id.to_i if @lights[id].is_a? Light @lights[id].handle_json info else @lights[id] = Light.new(self, id, info) changed = true end end @lights.select! do |id, light| incl = @config['lights'].include? id.to_s changed ||= !incl incl end set_name @config['config']['name'] unless @name @serial ||= @config['config']['mac'].gsub(':', '').downcase @registered = true unless @groups[0].is_a? Group @groups[0] = Group.new(self, 0) get_api '/groups/0', :info do |response| status, result = check_json response if status && @groups[0] @groups[0].handle_json result end end end @config['groups'].each do |id, info| if @groups[id.to_i].is_a? Group @groups[id.to_i].handle_json info else @groups[id.to_i] = Group.new(self, id.to_i, info) changed = true end end @groups.select! do |id, light| incl = @config['groups'].include?(id.to_s) || id == 0 changed ||= !incl incl end @config['scenes'].each do |id, info| if @scenes[id].is_a? Scene @scenes[id].handle_json info else @scenes[id] = Scene.new(self, id, info) changed = true end end @scenes.select! do |id, scene| incl = @config['scenes'].include?(id.to_s) changed ||= !incl incl end wl = @config['config']['whitelist'] if wl != @whitelist @whitelist = wl changed = true end if changed @scenes = Hash[@scenes.sort_by{|id, s| s.name}] end # TODO: schedules, rules, sensors, etc. scan_status true if first_update || @lightscan['lastscan'] == 'active' Bridge.notify_bridge_callbacks self, true if first_update || changed end rescue => e log_e e, "Bridge #{@serial} update raised an exception" status = false result = e end result = changed if status notify_update_callbacks status, result yield status, result end end |
#updated? ⇒ Boolean
Returns whether the Bridge object has had at least one successful update from #update.
437 438 439 |
# File 'lib/nlhue/bridge.rb', line 437 def updated? @config.is_a? Hash end |
#verified? ⇒ Boolean
Indicates whether verification succeeded. A Hue bridge has been verified to exist at the address given to the constructor or to #addr= if this returns true. Use #verify to perform verification if this returns false.
445 446 447 |
# File 'lib/nlhue/bridge.rb', line 445 def verified? @verified end |
#verify(&block) ⇒ Object
Calls the given block with true or false if verification by description.xml succeeds or fails. If verification has already been performed, the block will be called immediately with true.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/nlhue/bridge.rb', line 132 def verify &block if @verified yield true return true end @request_queue.get '/description.xml', :info, 4 do |result| puts "Description result: #{result.inspect}" # XXX if result.is_a?(Hash) && result[:status] == 200 @desc = REXML::Document.new result[:content] @desc.write($stdout, 4, true) # XXX @desc.elements.each('friendlyName') do |el| puts "Friendly name: #{@name}" # XXX set_name el.text end @desc.elements.each('serialNumber') do |el| puts "Serial number: #{@serial}" # XXX @serial = el.text.downcase end @desc.elements.each('modelName') do |el| puts "modelName: #{el.text}" # XXX if el.text.include? 'Philips hue' @verified = true end end # FIXME: Delete this line when converted to em-http-request; this # works around the empty :content returned by EM::HttpClient # # See commits: # 34110773fc45bfdd56c32972650f9d947d8fac78 # 6d8d7a0566e3c51c3ab15eb2358dde3e518594d3 @verified = true end begin yield @verified rescue => e log_e e, "Error notifying block after verification" end end end |