huebot 0.5.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +96 -27
- data/bin/huebot +35 -32
- data/lib/huebot/bot.rb +82 -39
- data/lib/huebot/cli/helpers.rb +177 -0
- data/lib/huebot/cli/runner.rb +78 -0
- data/lib/huebot/cli.rb +2 -139
- data/lib/huebot/client.rb +5 -4
- data/lib/huebot/compiler/api_v1.rb +304 -0
- data/lib/huebot/compiler.rb +11 -149
- data/lib/huebot/device_mapper.rb +38 -24
- data/lib/huebot/device_state.rb +5 -1
- data/lib/huebot/group.rb +10 -3
- data/lib/huebot/light.rb +10 -3
- data/lib/huebot/program.rb +71 -21
- data/lib/huebot/version.rb +1 -1
- data/lib/huebot.rb +3 -22
- metadata +34 -3
data/lib/huebot/device_mapper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Huebot
|
2
2
|
class DeviceMapper
|
3
|
-
Unmapped = Class.new(
|
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.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
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
|
41
|
+
when :all
|
45
42
|
@all
|
46
43
|
else
|
47
|
-
@devices_by_var[id]
|
48
|
-
end
|
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
|
data/lib/huebot/device_state.rb
CHANGED
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
|
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
|
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
|
data/lib/huebot/program.rb
CHANGED
@@ -1,32 +1,82 @@
|
|
1
1
|
module Huebot
|
2
2
|
class Program
|
3
|
-
|
4
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
data/lib/huebot/version.rb
CHANGED
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:
|
4
|
+
version: 1.1.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-
|
12
|
-
dependencies:
|
11
|
+
date: 2023-12-19 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
|