huebot 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  module Huebot
2
2
  class DeviceMapper
3
- Unmapped = Class.new(StandardError)
3
+ Unmapped = Class.new(Error)
4
4
 
5
5
  def initialize(bridge, inputs = [])
6
6
  all_lights, all_groups = bridge.lights, bridge.groups
@@ -9,43 +9,57 @@ module Huebot
9
9
  @lights_by_name = all_lights.reduce({}) { |a, l| a[l.name] = l; a }
10
10
  @groups_by_id = all_groups.reduce({}) { |a, g| a[g.id] = g; a }
11
11
  @groups_by_name = all_groups.reduce({}) { |a, g| a[g.name] = g; a }
12
- @devices_by_var = inputs.each_with_index.reduce({}) { |a, (x, idx)|
13
- dev = case x
14
- when LightInput then @lights_by_id[x.val] || @lights_by_name[x.val]
15
- when GroupInput then @groups_by_id[x.val] || @groups_by_name[x.val]
16
- else raise "Invalid input: #{x}"
17
- end || raise(Unmapped, "Could not find #{x.class.name[8..-6].downcase} with id or name '#{x.val}'")
18
- a["$#{idx + 1}"] = dev
19
- a
12
+ @devices_by_var = inputs.each_with_index.each_with_object({}) { |(x, idx), obj|
13
+ obj[idx + 1] =
14
+ case x
15
+ when Light::Input then @lights_by_id[x.val.to_i] || @lights_by_name[x.val]
16
+ when Group::Input then @groups_by_id[x.val.to_i] || @groups_by_name[x.val]
17
+ else raise Error, "Invalid input: #{x}"
18
+ end || raise(Unmapped, "Could not find #{x.class.name[8..-6].downcase} with id or name '#{x.val}'")
20
19
  }
21
20
  @all = @devices_by_var.values
22
21
  end
23
22
 
23
+ def each
24
+ if block_given?
25
+ @all.each { |device| yield device }
26
+ else
27
+ @all.each
28
+ end
29
+ end
30
+
24
31
  def light!(id)
25
- case id
26
- when Integer
27
- @lights_by_id[id]
28
- when String
29
- @lights_by_name[id]
30
- end || (raise Unmapped, "Unmapped light '#{id}'")
32
+ @lights_by_id[id] || @lights_by_name[id] || (raise Unmapped, "Unmapped light '#{id}'")
31
33
  end
32
34
 
33
35
  def group!(id)
34
- case id
35
- when Integer
36
- @groups_by_id[id]
37
- when String
38
- @groups_by_name[id]
39
- end || (raise Unmapped, "Unmapped group '#{id}'")
36
+ @groups_by_id[id] || @groups_by_name[id] || (raise Unmapped, "Unmapped group '#{id}'")
40
37
  end
41
38
 
42
39
  def var!(id)
43
40
  case id
44
- when "$all"
41
+ when :all
45
42
  @all
46
43
  else
47
- @devices_by_var[id]
48
- end || (raise Unmapped, "Unmapped device '#{id}'")
44
+ @devices_by_var[id] || (raise Unmapped, "Unmapped device '#{id}'")
45
+ end
46
+ end
47
+
48
+ def missing_lights(names)
49
+ names - @lights_by_name.keys
50
+ end
51
+
52
+ def missing_groups(names)
53
+ names - @groups_by_name.keys
54
+ end
55
+
56
+ def missing_vars(vars)
57
+ missing = vars - @devices_by_var.keys
58
+ if @all.any?
59
+ missing - [:all]
60
+ else
61
+ missing
62
+ end
49
63
  end
50
64
  end
51
65
  end
@@ -1,7 +1,11 @@
1
1
  module Huebot
2
2
  module DeviceState
3
3
  def set_state(state)
4
- client.put!(state_url, state)
4
+ client.put!(state_change_url, state)
5
+ end
6
+
7
+ def get_state
8
+ client.get!(url).fetch("state")
5
9
  end
6
10
  end
7
11
  end
data/lib/huebot/group.rb CHANGED
@@ -1,22 +1,29 @@
1
1
  module Huebot
2
2
  class Group
3
+ #
4
+ # Struct for specifying a Group input (id or name)
5
+ #
6
+ # @attr val [Integer|String] id or name
7
+ #
8
+ Input = Struct.new(:val)
9
+
3
10
  include DeviceState
4
11
  attr_reader :client, :id, :name
5
12
 
6
13
  def initialize(client, id, attrs)
7
14
  @client = client
8
- @id = id
15
+ @id = id.to_i
9
16
  @name = attrs.fetch("name")
10
17
  @attrs = attrs
11
18
  end
12
19
 
13
20
  private
14
21
 
15
- def state_url
22
+ def state_change_url
16
23
  url "/action"
17
24
  end
18
25
 
19
- def url(path)
26
+ def url(path = "")
20
27
  "/groups/#{id}#{path}"
21
28
  end
22
29
  end
data/lib/huebot/light.rb CHANGED
@@ -1,22 +1,29 @@
1
1
  module Huebot
2
2
  class Light
3
+ #
4
+ # Struct for specifying a Light input (id or name)
5
+ #
6
+ # @attr val [Integer|String] id or name
7
+ #
8
+ Input = Struct.new(:val)
9
+
3
10
  include DeviceState
4
11
  attr_reader :client, :id, :name
5
12
 
6
13
  def initialize(client, id, attrs)
7
14
  @client = client
8
- @id = id
15
+ @id = id.to_i
9
16
  @name = attrs.fetch("name")
10
17
  @attrs = attrs
11
18
  end
12
19
 
13
20
  private
14
21
 
15
- def state_url
22
+ def state_change_url
16
23
  url "/state"
17
24
  end
18
25
 
19
- def url(path)
26
+ def url(path = "")
20
27
  "/lights/#{id}#{path}"
21
28
  end
22
29
  end
@@ -1,32 +1,82 @@
1
1
  module Huebot
2
2
  class Program
3
- Transition = Struct.new(:wait, :state, :devices)
4
- ParallelTransition = Struct.new(:wait, :children)
3
+ #
4
+ # Struct for storing a program's Intermediate Representation and source filepath.
5
+ #
6
+ # @attr tokens [Hash]
7
+ # @attr filepath [String]
8
+ # @attr api_version [Float] API version
9
+ #
10
+ Src = Struct.new(:tokens, :filepath, :api_version) do
11
+ def default_name
12
+ File.basename(filepath, ".*")
13
+ end
14
+ end
5
15
 
6
- attr_accessor :name
7
- attr_accessor :initial_state
8
- attr_accessor :transitions
9
- attr_accessor :final_state
10
- attr_accessor :loop
11
- attr_accessor :loops
12
- attr_accessor :errors
13
- attr_accessor :warnings
14
-
15
- def initialize
16
- @name = nil
17
- @initial_state = nil
18
- @transitions = []
19
- @final_state = nil
20
- @loop = false
21
- @loops = 0
22
- @errors = []
23
- @warnings = []
16
+ module AST
17
+ Node = Struct.new(:instruction, :children, :errors, :warnings)
18
+
19
+ Transition = Struct.new(:state, :devices, :sleep)
20
+ SerialControl = Struct.new(:loop, :sleep)
21
+ ParallelControl = Struct.new(:loop, :sleep)
22
+
23
+ InfiniteLoop = Struct.new(:pause)
24
+ CountedLoop = Struct.new(:n, :pause)
25
+ TimerLoop = Struct.new(:hours, :minutes, :pause)
26
+ DeadlineLoop = Struct.new(:stop_time, :pause)
27
+
28
+ DeviceRef = Struct.new(:ref)
29
+ Light = Struct.new(:name)
30
+ Group = Struct.new(:name)
31
+ NoOp = Struct.new(:x)
24
32
  end
25
33
 
34
+ attr_accessor :name
35
+ attr_accessor :api_version
36
+ attr_accessor :data
37
+
26
38
  def valid?
27
39
  errors.empty?
28
40
  end
29
41
 
30
- alias_method :loop?, :loop
42
+ # Returns all light names hard-coded into the program
43
+ def light_names(node = data)
44
+ devices(AST::Light).uniq.map(&:name)
45
+ end
46
+
47
+ # Returns all group names hard-coded into the program
48
+ def group_names(node = data)
49
+ devices(AST::Group).uniq.map(&:name)
50
+ end
51
+
52
+ # Returns all device refs (e.g. $all, $1, $2) in the program
53
+ def device_refs(node = data)
54
+ devices(AST::DeviceRef).uniq.map(&:ref)
55
+ end
56
+
57
+ def errors(node = data)
58
+ node.children.reduce(node.errors) { |errors, child|
59
+ errors + child.errors
60
+ }
61
+ end
62
+
63
+ def warnings(node = data)
64
+ node.children.reduce(node.warnings) { |warnings, child|
65
+ warnings + child.warnings
66
+ }
67
+ end
68
+
69
+ private
70
+
71
+ def devices(type, node = data)
72
+ case node.instruction
73
+ when AST::Transition
74
+ node.instruction.devices.select { |d| d.is_a? type }
75
+ when AST::SerialControl, AST::ParallelControl
76
+ node.children.map { |n| devices type, n }.flatten
77
+ else
78
+ []
79
+ end
80
+ end
31
81
  end
32
82
  end
@@ -1,4 +1,4 @@
1
1
  module Huebot
2
2
  # Gem version
3
- VERSION = '0.5.0'
3
+ VERSION = '1.0.0'
4
4
  end
data/lib/huebot.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  module Huebot
2
+ Error = Class.new(StandardError)
3
+
2
4
  autoload :Config, 'huebot/config'
3
5
  autoload :Client, 'huebot/client'
6
+ autoload :CLI, 'huebot/cli'
4
7
  autoload :Bridge, 'huebot/bridge'
5
8
  autoload :DeviceState, 'huebot/device_state'
6
9
  autoload :Light, 'huebot/light'
@@ -10,26 +13,4 @@ module Huebot
10
13
  autoload :Compiler, 'huebot/compiler'
11
14
  autoload :Bot, 'huebot/bot'
12
15
  autoload :VERSION, 'huebot/version'
13
-
14
- #
15
- # Struct for storing a program's Intermediate Representation and source filepath.
16
- #
17
- # @attr ir [Hash]
18
- # @attr filepath [String]
19
- #
20
- ProgramSrc = Struct.new(:ir, :filepath)
21
-
22
- #
23
- # Struct for specifying a Light input (id or name)
24
- #
25
- # @attr val [Integer|String] id or name
26
- #
27
- LightInput = Struct.new(:val)
28
-
29
- #
30
- # Struct for specifying a Group input (id or name)
31
- #
32
- # @attr val [Integer|String] id or name
33
- #
34
- GroupInput = Struct.new(:val)
35
16
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: huebot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Hollinger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-08 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-12-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
13
41
  description: Declare and run YAML programs for Philips Hue devices
14
42
  email: jordan.hollinger@gmail.com
15
43
  executables:
@@ -23,8 +51,11 @@ files:
23
51
  - lib/huebot/bot.rb
24
52
  - lib/huebot/bridge.rb
25
53
  - lib/huebot/cli.rb
54
+ - lib/huebot/cli/helpers.rb
55
+ - lib/huebot/cli/runner.rb
26
56
  - lib/huebot/client.rb
27
57
  - lib/huebot/compiler.rb
58
+ - lib/huebot/compiler/api_v1.rb
28
59
  - lib/huebot/config.rb
29
60
  - lib/huebot/device_mapper.rb
30
61
  - lib/huebot/device_state.rb