esphome 0.6.0 → 1.1.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/exe/esphome-monitor +16 -14
  3. data/exe/esphome-serial-proxy +132 -0
  4. data/lib/esphome/action.rb +55 -0
  5. data/lib/esphome/api/README.md +3 -0
  6. data/lib/esphome/api/api.proto +2756 -0
  7. data/lib/esphome/api/api_options.proto +120 -0
  8. data/lib/esphome/api/api_options_pb.rb +20 -0
  9. data/lib/esphome/api/api_pb.rb +229 -0
  10. data/lib/esphome/api.rb +182 -0
  11. data/lib/esphome/cli/colors.rb +44 -0
  12. data/lib/esphome/cli/completion.rb +48 -0
  13. data/lib/esphome/cli/entities/button.rb +18 -0
  14. data/lib/esphome/cli/entities/climate.rb +196 -0
  15. data/lib/esphome/cli/entities/cover.rb +116 -0
  16. data/lib/esphome/cli/entities/date.rb +27 -0
  17. data/lib/esphome/cli/entities/date_time.rb +29 -0
  18. data/lib/esphome/cli/entities/form.rb +111 -0
  19. data/lib/esphome/cli/entities/lock.rb +20 -0
  20. data/lib/esphome/cli/entities/menu.rb +83 -0
  21. data/lib/esphome/cli/entities/number.rb +37 -0
  22. data/lib/esphome/cli/entities/select.rb +16 -0
  23. data/lib/esphome/cli/entities/subfields.rb +63 -0
  24. data/lib/esphome/cli/entities/switch.rb +18 -0
  25. data/lib/esphome/cli/entities/text.rb +16 -0
  26. data/lib/esphome/cli/entities/time.rb +40 -0
  27. data/lib/esphome/cli/entity.rb +78 -0
  28. data/lib/esphome/cli/monitor.rb +441 -0
  29. data/lib/esphome/dashboard.rb +86 -0
  30. data/lib/esphome/device.rb +416 -0
  31. data/lib/esphome/entities/binary_sensor.rb +66 -0
  32. data/lib/esphome/entities/button.rb +13 -0
  33. data/lib/esphome/entities/climate.rb +259 -0
  34. data/lib/esphome/entities/cover.rb +135 -0
  35. data/lib/esphome/entities/date.rb +23 -0
  36. data/lib/esphome/entities/date_time.rb +21 -0
  37. data/lib/esphome/entities/fan.rb +89 -0
  38. data/lib/esphome/entities/light.rb +158 -0
  39. data/lib/esphome/entities/lock.rb +53 -0
  40. data/lib/esphome/entities/number.rb +56 -0
  41. data/lib/esphome/entities/select.rb +27 -0
  42. data/lib/esphome/entities/sensor.rb +49 -0
  43. data/lib/esphome/entities/switch.rb +24 -0
  44. data/lib/esphome/entities/text.rb +36 -0
  45. data/lib/esphome/entities/text_sensor.rb +10 -0
  46. data/lib/esphome/entities/time.rb +39 -0
  47. data/lib/esphome/entity.rb +146 -0
  48. data/lib/esphome/error.rb +28 -0
  49. data/lib/esphome/serial_proxy.rb +372 -0
  50. data/lib/esphome/version.rb +5 -0
  51. data/lib/esphome.rb +5 -0
  52. data/lib/httpx/plugins/websocket.rb +62 -0
  53. data/lib/websocket/driver/httpx.rb +74 -0
  54. metadata +55 -5
  55. data/exe/esphome-update-all +0 -66
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a5451a87964a40d165ef4ca77b495e96c1cefb3a5868199713291adf524fe41
4
- data.tar.gz: 3019f79e68e524def14f2070a2df85e33029d06ade92449a7bab773d06da345d
3
+ metadata.gz: 33d62455a361134b7827505b3522fe5793cec979e80341d413faf96dcdb28e71
4
+ data.tar.gz: 5e40a30af957deca20e72bade19dd9920b250816bc3d3e94da3d38704f7f6f3b
5
5
  SHA512:
6
- metadata.gz: c6fb19598d6575c3466a9f6aadd6dc4c25b36bfe516a8749bdc258d9a994b0ce2fba96356f933675babe033432923105edadfdc72243373aacaf5a7e798820c1
7
- data.tar.gz: 40fe976911ca7cf97c93f482b47038e951916457faca363c73a53573594928f51938a83626753d5bd7e1e2ffe76ec037a67460428240e08c1911abcc66571063
6
+ metadata.gz: 1aab44a24e5fce3acd11c7d37c0d0995cd70e472bda890012218a3db3f99202f6bd4ffbd5cbadd942957cdf8f929ae862096d5779d16d967cd1e264059795ac3
7
+ data.tar.gz: 03f1fb2e2bee356d445b58d3a38eebb357d5df249d8340a3ca099b5a76447cf1979bf19a93ffd1474b5b283a82880504d3c8f7effc2271eb234d590e5ca5852d
data/exe/esphome-monitor CHANGED
@@ -3,13 +3,20 @@
3
3
 
4
4
  require "optparse"
5
5
 
6
+ require "esphome/cli/completion"
6
7
  require "esphome/cli/monitor"
7
8
 
9
+ if ENV["COMP_LINE"]
10
+ ESPHome::Cli::Completion.run
11
+ exit
12
+ end
13
+
8
14
  actions = true
9
15
  log_level = :info
10
16
  connection_log_level = :warn
11
17
  device_log_level = :debug
12
18
  dump_config = false
19
+ port = 6053
13
20
  opts = OptionParser.new do |opts|
14
21
  opts.banner = <<~TEXT
15
22
  Usage: esphome-monitor ([<uri>] <device_name> | <address> <encryption_key>)
@@ -18,6 +25,9 @@ opts = OptionParser.new do |opts|
18
25
  If URI is omitted, it defaults to http://localhost:6052/
19
26
  TEXT
20
27
 
28
+ opts.on("--port=VALUE", Integer, "Device port to connect to (default 6053)") do |value|
29
+ port = value
30
+ end
21
31
  opts.on("--[no-]actions", "Subscribe to Home Assistant actions (default on)") do |v|
22
32
  actions = v
23
33
  end
@@ -41,7 +51,7 @@ end
41
51
  opts.parse!
42
52
 
43
53
  if ARGV.size == 1
44
- uri = "http://localhost:6052/"
54
+ uri = ESPHome::Dashboard::DEFAULT_URI
45
55
  device_name = ARGV[0]
46
56
  elsif ARGV.size == 2 && ARGV[0].include?(":")
47
57
  uri, device_name = ARGV
@@ -55,22 +65,14 @@ end
55
65
  if uri
56
66
  require "esphome/dashboard"
57
67
 
58
- dashboard = ESPHome::Dashboard.new(uri)
59
-
60
- device = dashboard.devices.find { |d| d["name"] == device_name }
61
- unless device
62
- warn "Device not found: #{device_name}"
63
- exit 1
64
- end
65
-
66
- address = device["address"]
67
- encryption_key = dashboard.encryption_key(device["configuration"])
68
- unless encryption_key
69
- warn "No encryption key found for device #{device_name}"
68
+ begin
69
+ address, encryption_key = ESPHome::Dashboard.address_and_encryption_key(uri, device_name)
70
+ rescue ESPHome::DashboardError => e
71
+ warn e.message
70
72
  exit 1
71
73
  end
72
74
  end
73
75
 
74
- device = ESPHome::Device.new(address, encryption_key)
76
+ device = ESPHome::Device.new(address, encryption_key, port:)
75
77
 
76
78
  ESPHome::Cli::Monitor.run(device, connection_log_level:, device_log_level:, log_level:, actions:, dump_config:)
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "io/console"
5
+ require "optparse"
6
+
7
+ require "esphome/cli/completion"
8
+
9
+ if ENV["COMP_LINE"]
10
+ ESPHome::Cli::Completion.run
11
+ exit
12
+ end
13
+
14
+ require "esphome/serial_proxy"
15
+
16
+ baud = nil
17
+ data_bits = nil
18
+ parity = nil
19
+ stop_bits = nil
20
+
21
+ opts = OptionParser.new do |opts|
22
+ opts.banner = <<~TEXT
23
+ Usage: esphome-serial-proxy ([<uri>] <device_name> [instance] | <address> <encryption_key> [instance])
24
+
25
+ Examples:
26
+ esphome-serial-proxy my_device
27
+ esphome-serial-proxy http://localhost:6052/ my_device uart0
28
+ esphome-serial-proxy 192.168.1.10 BASE64_ENCRYPTION_KEY 1
29
+ TEXT
30
+
31
+ opts.on("--baud=VALUE", Integer, "Serial baud rate") do |value|
32
+ baud = value
33
+ end
34
+ opts.on("--data-bits=VALUE", Integer, "Serial data bits") do |value|
35
+ data_bits = value
36
+ end
37
+ opts.on("--parity=VALUE", "Serial parity (`none`, `even`, or `odd`)") do |value|
38
+ parity = value.to_sym
39
+ end
40
+ opts.on("--stop-bits=VALUE", Integer, "Serial stop bits") do |value|
41
+ stop_bits = value
42
+ end
43
+ opts.on("-h", "--help", "Show this help message") do
44
+ puts opts
45
+ exit
46
+ end
47
+ end
48
+ opts.parse!
49
+
50
+ dashboard_uri = nil
51
+ device_name = nil
52
+ address = nil
53
+ encryption_key = nil
54
+ instance = nil
55
+
56
+ if ARGV.size == 1
57
+ dashboard_uri = ESPHome::Dashboard::DEFAULT_URI
58
+ device_name = ARGV[0]
59
+ elsif ARGV.size == 2 && ARGV[0].include?(":")
60
+ dashboard_uri, device_name = ARGV
61
+ elsif ARGV.size == 2
62
+ address, encryption_key = ARGV
63
+ elsif ARGV.size == 3 && ARGV[0].include?(":")
64
+ dashboard_uri, device_name, instance = ARGV
65
+ elsif ARGV.size == 3
66
+ address, encryption_key, instance = ARGV
67
+ else
68
+ warn opts
69
+ exit(-1)
70
+ end
71
+
72
+ if dashboard_uri
73
+ require "esphome/dashboard"
74
+
75
+ begin
76
+ address, encryption_key = ESPHome::Dashboard.address_and_encryption_key(dashboard_uri, device_name)
77
+ rescue ESPHome::DashboardError => e
78
+ warn e.message
79
+ exit 1
80
+ end
81
+ end
82
+
83
+ stdin_thread = nil
84
+ interactive = $stdin.tty?
85
+ session = proc do
86
+ $stdin.binmode
87
+ $stdout.binmode
88
+ $stderr.binmode
89
+ $stdout.sync = true
90
+
91
+ ESPHome::SerialProxy.open(address,
92
+ encryption_key,
93
+ instance,
94
+ baud:,
95
+ data_bits:,
96
+ parity:,
97
+ stop_bits:) do |proxy|
98
+ stdin_thread = Thread.new do
99
+ Kernel.loop do
100
+ chunk = $stdin.readpartial(64 * 1024)
101
+ if interactive && (eof = chunk.index("\x04"))
102
+ proxy.write(chunk.byteslice(0, eof)) if eof.positive?
103
+ proxy.close
104
+ break
105
+ end
106
+
107
+ proxy.write(chunk)
108
+ end
109
+ rescue EOFError
110
+ nil
111
+ end
112
+
113
+ begin
114
+ Kernel.loop do
115
+ $stdout.write(proxy.readpartial(64 * 1024))
116
+ end
117
+ rescue EOFError
118
+ nil
119
+ ensure
120
+ stdin_thread.kill if stdin_thread&.alive?
121
+ stdin_thread&.join
122
+ end
123
+ end
124
+ end
125
+
126
+ if interactive
127
+ $stdin.raw(intr: true) do
128
+ session.call
129
+ end
130
+ else
131
+ session.call
132
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ESPHome
4
+ class Action
5
+ class << self
6
+ def from_protobuf(message)
7
+ data = message.data.to_h { |kv| [kv.key, kv.value] }
8
+ data_template = message.data_template.to_h { |kv| [kv.key, kv.value] }
9
+ variables = message.variables.to_h { |kv| [kv.key, kv.value] }
10
+ if message.is_event
11
+ if message.service == TagScanned::SERVICE &&
12
+ data.keys == ["tag_id"] &&
13
+ data_template.empty? &&
14
+ variables.empty?
15
+ TagScanned.new(data["tag_id"])
16
+ else
17
+ Event.new(message.service, data, data_template, variables)
18
+ end
19
+ else
20
+ Action.new(message.service, data, data_template, variables)
21
+ end
22
+ end
23
+ end
24
+
25
+ attr_reader :service, :data, :data_template, :variables
26
+
27
+ def initialize(service, data = {}, data_template = {}, variables = {})
28
+ @service = service
29
+ @data = data
30
+ @data_template = data_template
31
+ @variables = variables
32
+ end
33
+
34
+ def inspect
35
+ "#<#{self.class.name} service=#{service} " \
36
+ "data=#{data.inspect} " \
37
+ "data_template=#{data_template.inspect} " \
38
+ "variables=#{variables.inspect}>"
39
+ end
40
+ end
41
+
42
+ class Event < Action; end
43
+
44
+ class TagScanned < Event
45
+ SERVICE = "esphome.tag_scanned"
46
+
47
+ def initialize(tag_id)
48
+ super(SERVICE, { "tag_id" => tag_id })
49
+ end
50
+
51
+ def inspect
52
+ "#<#{self.class.name} tag_id=#{data["tag_id"].inspect}>"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ Just copy api.proto from esphome's repository and re-add `option ruby_package = "ESPHome::Api";` at the top.
2
+ Then regenerate with `protoc --ruby_out=. api.proto api_options.proto`, and finally edit the `require` in api_pb.rb to be `require_relative`.
3
+ Be sure to add any new messages to api.rb, and check for changes in the messages themselves.