adafruit-io 3.0.0 → 4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d3a797bff9e66a705fc31f4572f9158dde61f9253e5e3bf501b8d59adb6df5c
4
- data.tar.gz: 40ad6e3b91d36b1b977584224c7c62448aa924aa78a8dc46beda1d58368d98f4
3
+ metadata.gz: a1d57d2998069e7dda6fd18ab4dac69cf1ce98d67e84568046118bda4bb14bf7
4
+ data.tar.gz: 6d31d21c4ff9186492d93202dc27a1359b935d5e33d8ee57d0f376c63a6ea33c
5
5
  SHA512:
6
- metadata.gz: 56efae94520d3ba34ab840877dfa9e16c2a6fd852bba785adec2ab24ed5c0243ab7d2aefcef4f473caf218affe11cb1f1daf519cfb34407e3a1fb8248efb827c
7
- data.tar.gz: a81845c9affa024284f07203d2c6dce47d442a531b216dcb139028c1b7e6ebf1918c75a2b89e813d58d95d17c8efa6a6934c6b6f803acc6afa7eed63fdb250c3
6
+ metadata.gz: 61b089f5f60170a8e2133c66f6db86ab631ab2820d302ad905ec26e1a0d65b9954a02682b264063580bbd7400d6c693d0880c4b5627b7877c706c5440d0da3d3
7
+ data.tar.gz: f38e367aabdd8e5f86edf645aea9697dbb248e229b2f4adbb6427f984ea2da1ea837cdbc09fe935534cac505a8822b2581cbb3c2933caa15494726739b915fdf
data/adafruit-io.gemspec CHANGED
@@ -18,13 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
+ spec.required_ruby_version = ">= 3.3"
21
22
  spec.licenses = ['MIT']
22
23
 
23
24
  spec.add_dependency "faraday", "~> 2.14"
24
- spec.add_dependency "faraday-multipart", "~> 1.0"
25
- spec.add_dependency "activesupport", "~> 8.0"
26
25
  spec.add_dependency "mqtt", "~> 0.7"
27
26
 
28
- spec.add_development_dependency "bundler", "~> 2.7"
29
27
  spec.add_development_dependency "rake", "~> 13.2"
30
28
  end
@@ -1,18 +1,20 @@
1
+ require 'adafruit/io/errors'
2
+
1
3
  module Adafruit
2
4
  module IO
3
5
  module Arguments
4
- class ArgumentError < StandardError; end
5
-
6
6
  # Allows us to give a username during client initialization or with a specific method.
7
7
  def extract_username(args)
8
8
  username = @username
9
9
 
10
10
  if args.last.is_a?(Hash) && args.last.has_key?(:username)
11
- username = args.last.delete(:username)
11
+ options = args.last.dup
12
+ username = options.delete(:username)
13
+ args = args[0...-1] + [options]
12
14
  end
13
15
 
14
16
  if username.nil?
15
- raise "cannot make request when username is nil"
17
+ raise ArgumentError.new("cannot make request when username is nil")
16
18
  end
17
19
 
18
20
  [ username, args ]
@@ -34,10 +36,11 @@ module Adafruit
34
36
  record_or_key
35
37
  elsif record_or_key.is_a?(Hash) && (record_or_key.has_key?('key') || record_or_key.has_key?(:key))
36
38
  record_or_key['key'] || record_or_key[:key]
37
- elsif record_or_key.respond_to?(:key)
39
+ elsif !record_or_key.is_a?(Hash) && record_or_key.respond_to?(:key)
40
+ # Hash#key(value) exists, so plain hashes must not land here
38
41
  record_or_key.key
39
42
  else
40
- raise 'unrecognized object or key value in arguments'
43
+ raise ArgumentError.new('unrecognized object or key value in arguments')
41
44
  end
42
45
  end
43
46
 
@@ -53,18 +56,23 @@ module Adafruit
53
56
  elsif record_or_id.respond_to?(:id)
54
57
  record_or_id.id
55
58
  else
56
- raise 'unrecognized object or id value in arguments'
59
+ raise ArgumentError.new('unrecognized object or id value in arguments')
57
60
  end
58
61
  end
59
62
 
60
- # Get a filtered list of parameters from the next argument
63
+ # Get a filtered list of parameters from the next argument. Accepts
64
+ # either symbol or string keys.
61
65
  def get_query_from_arguments(arguments, params)
62
66
  query = {}
63
67
  options = arguments.shift
64
68
  return query if options.nil?
65
69
 
66
70
  params.each do |param|
67
- query[param] = options[param.to_sym] if options.has_key?(param.to_sym)
71
+ if options.has_key?(param.to_sym)
72
+ query[param] = options[param.to_sym]
73
+ elsif options.has_key?(param.to_s)
74
+ query[param] = options[param.to_s]
75
+ end
68
76
  end
69
77
  query
70
78
  end
@@ -38,12 +38,17 @@ module Adafruit
38
38
  delete api_url(username, 'dashboards', dashboard_key, 'blocks', block_id)
39
39
  end
40
40
 
41
- # Update a block
41
+ # Update a block. Attributes can be given in the same hash as
42
+ # dashboard_key and key, or as a separate second hash:
43
+ #
44
+ # client.update_block(dashboard_key: 'db', key: 1, name: 'new')
45
+ # client.update_block({ dashboard_key: 'db', key: 1 }, { name: 'new' })
42
46
  def update_block(*args)
43
47
  username, arguments = extract_username(args)
44
48
  dashboard_key = require_argument(arguments, :dashboard_key)
49
+ options = arguments.first
45
50
  block_id = get_key_from_arguments(arguments)
46
- block_attrs = valid_block_attrs(arguments)
51
+ block_attrs = valid_block_attrs(arguments.empty? ? [options] : arguments)
47
52
 
48
53
  put api_url(username, 'dashboards', dashboard_key, 'blocks', block_id), block_attrs
49
54
  end
@@ -1,3 +1,5 @@
1
+ require 'time'
2
+
1
3
  module Adafruit
2
4
  module IO
3
5
  class Client
@@ -53,7 +55,7 @@ module Adafruit
53
55
  values = arguments.shift
54
56
 
55
57
  if values.nil? || !values.is_a?(Array)
56
- raise "expected batch values to be an array"
58
+ raise Adafruit::IO::Arguments::ArgumentError.new("expected batch values to be an array")
57
59
  end
58
60
 
59
61
  if !values.first.is_a?(Hash)
@@ -2,7 +2,7 @@ module Adafruit
2
2
  module IO
3
3
  class Client
4
4
  module Permissions
5
- VALID_TYPES = %(feed group dashboard)
5
+ VALID_TYPES = %w(feed group dashboard).freeze
6
6
 
7
7
  # Get all permissions for a resource.
8
8
  #
@@ -25,13 +25,18 @@ module Adafruit
25
25
  get api_url(username, pluralize_type(arguments[0]), arguments[1], 'acl', arguments[2])
26
26
  end
27
27
 
28
+ # client.create_permission(TYPE, KEY, { scope: 'public', mode: 'r' })
28
29
  def create_permission(*args)
29
30
  username, arguments = extract_username(args)
30
31
 
31
32
  assert_argument_size(arguments, 2)
32
33
  assert_resource_type(arguments[0])
33
34
 
34
- permission_attrs = arguments.pop
35
+ permission_attrs = arguments[2]
36
+ if !permission_attrs.is_a?(Hash)
37
+ raise Adafruit::IO::Arguments::ArgumentError.new('create_permission requires resource type (string), resource key (string), and a Hash of permission attributes, e.g. { scope: "public", mode: "r" }')
38
+ end
39
+
35
40
  post api_url(username, pluralize_type(arguments[0]), arguments[1], 'acl'), permission_attrs
36
41
  end
37
42
 
@@ -20,9 +20,9 @@ module Adafruit
20
20
 
21
21
  # Create a token. No attributes need to be passed in.
22
22
  def create_token(*args)
23
- username, arguments = extract_username(args)
23
+ username, _ = extract_username(args)
24
24
 
25
- post api_url(username, 'tokens')
25
+ post api_url(username, 'tokens'), {}
26
26
  end
27
27
 
28
28
  def delete_token(*args)
@@ -36,9 +36,7 @@ module Adafruit
36
36
  #
37
37
  # @return [String]
38
38
  def inspect
39
- inspected = super
40
- inspected = inspected.gsub! @key, "#{@key[0..3]}#{'*' * (@key.size - 3)}" if @key
41
- inspected
39
+ "#<#{self.class.name} username=#{@username.inspect} api_endpoint=#{api_endpoint.inspect} key=#{masked_key.inspect}>"
42
40
  end
43
41
 
44
42
  def last_response
@@ -58,14 +56,19 @@ module Adafruit
58
56
 
59
57
  private
60
58
 
59
+ def masked_key
60
+ return nil if @key.nil?
61
+ return '*' * @key.size if @key.size <= 4
62
+
63
+ "#{@key[0..3]}#{'*' * (@key.size - 4)}"
64
+ end
65
+
61
66
  def conn
62
- if api_endpoint
63
- url = api_endpoint
64
- else
65
- url = 'https://io.adafruit.com'
66
- end
67
+ settings = [api_endpoint, @key, @debug]
68
+ return @conn if @conn && @conn_settings == settings
67
69
 
68
- Faraday.new(:url => url) do |c|
70
+ @conn_settings = settings
71
+ @conn = Faraday.new(:url => api_endpoint) do |c|
69
72
  c.headers['X-AIO-Key'] = @key
70
73
  c.headers['Accept'] = 'application/json'
71
74
  c.headers['User-Agent'] = "AdafruitIO-Ruby/#{VERSION} (#{RUBY_PLATFORM})"
@@ -0,0 +1,18 @@
1
+ module Adafruit
2
+ module IO
3
+ class Error < StandardError; end
4
+
5
+ class RequestError < Error
6
+ attr_reader :response
7
+
8
+ def initialize(message, response)
9
+ super(message)
10
+ @response = response
11
+ end
12
+ end
13
+
14
+ module Arguments
15
+ class ArgumentError < Adafruit::IO::Error; end
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,5 @@
1
1
  require 'mqtt'
2
+ require 'adafruit/io/errors'
2
3
 
3
4
  #
4
5
  # Adafruit::IO::MQTT provides a simple Adafruit IO aware wrapper around the
@@ -65,7 +66,7 @@ module Adafruit
65
66
 
66
67
  # Publish value to feed with given key
67
68
  def publish(key, value, location={})
68
- raise 'client is not connected' unless @client.connected?
69
+ raise Adafruit::IO::Error.new('client is not connected') unless @client.connected?
69
70
 
70
71
  topic = key_to_feed_topic(key)
71
72
  location = indifferent_keys(location)
@@ -83,8 +84,8 @@ module Adafruit
83
84
  # location data for this publish event.
84
85
  #
85
86
  def publish_group(key, values, location={})
86
- raise 'client is not connected' unless @client.connected?
87
- raise 'values must be a hash' unless values.is_a?(Hash)
87
+ raise Adafruit::IO::Error.new('client is not connected') unless @client.connected?
88
+ raise Adafruit::IO::Arguments::ArgumentError.new('values must be a hash') unless values.is_a?(Hash)
88
89
 
89
90
  topic = key_to_group_topic(key, false)
90
91
  location = indifferent_keys(location)
@@ -99,7 +100,7 @@ module Adafruit
99
100
  # Include the { last_value: true } option if you'd like the feed to
100
101
  # receive the last value immediately. (like MQTT retain)
101
102
  def subscribe(key, options={})
102
- raise 'client is not connected' unless @client.connected?
103
+ raise Adafruit::IO::Error.new('client is not connected') unless @client.connected?
103
104
 
104
105
  topic = key_to_feed_topic(key)
105
106
  @client.subscribe(topic)
@@ -110,7 +111,7 @@ module Adafruit
110
111
  end
111
112
 
112
113
  def unsubscribe(key)
113
- raise 'client is not connected' unless @client.connected?
114
+ raise Adafruit::IO::Error.new('client is not connected') unless @client.connected?
114
115
 
115
116
  topic = key_to_feed_topic(key)
116
117
  @client.unsubscribe(topic)
@@ -123,7 +124,7 @@ module Adafruit
123
124
  # JSON object whose keys are feed keys and whose values are the last
124
125
  # value received for that feed.
125
126
  def subscribe_group(key)
126
- raise 'client is not connected' unless @client.connected?
127
+ raise Adafruit::IO::Error.new('client is not connected') unless @client.connected?
127
128
 
128
129
  topic = key_to_group_topic(key)
129
130
  @client.subscribe(topic)
@@ -176,7 +177,7 @@ module Adafruit
176
177
  def payload_from_value_with_location(value, location)
177
178
  payload = { value: value.to_s }
178
179
 
179
- if location.has_key?('lat') && location.has_key?['lon']
180
+ if location.has_key?('lat') && location.has_key?('lon')
180
181
  %w(lat lon ele).each do |f|
181
182
  payload[f] = location[f]
182
183
  end
@@ -188,7 +189,7 @@ module Adafruit
188
189
  def payload_from_values_with_location(values, location)
189
190
  payload = { feeds: values }
190
191
 
191
- if location.has_key?('lat') && location.has_key?['lon']
192
+ if location.has_key?('lat') && location.has_key?('lon')
192
193
  payload[:location] = {}
193
194
 
194
195
  %w(lat lon ele).each do |f|
@@ -1,21 +1,13 @@
1
- require 'open-uri'
1
+ require 'adafruit/io/errors'
2
2
 
3
3
  module Adafruit
4
4
  module IO
5
- class RequestError < StandardError
6
- attr_reader :response
7
-
8
- def initialize(message, response)
9
- super(message)
10
- @response = response
11
- end
12
- end
13
-
14
5
  module RequestHandler
15
6
 
16
7
  attr_reader :last_response, :pagination
17
8
 
18
- def request(method, url, data = nil, options = nil)
9
+ def request(method, url, data = nil)
10
+ @pagination = nil
19
11
  @last_response = send(method, url, data)
20
12
  end
21
13
 
@@ -23,15 +15,15 @@ module Adafruit
23
15
  request(:handle_get, url, options)
24
16
  end
25
17
 
26
- def post(url, data, options = {})
27
- request :handle_post, url, data, options
18
+ def post(url, data)
19
+ request :handle_post, url, data
28
20
  end
29
21
 
30
- def put(url, data, options = {})
31
- request :handle_put, url, data, options
22
+ def put(url, data)
23
+ request :handle_put, url, data
32
24
  end
33
25
 
34
- def delete(url, options = {})
26
+ def delete(url)
35
27
  request :handle_delete, url
36
28
  end
37
29
 
@@ -44,27 +36,25 @@ module Adafruit
44
36
  def update_pagination(response)
45
37
  @pagination = nil
46
38
 
47
- if pagination_keys = response.headers.keys.grep(/x-pagination-/i)
48
- @pagination = {}
49
- pagination_keys.each do |k|
50
- @pagination[k.gsub(/x-pagination-/i, '')] = response.headers[k]
51
- end
39
+ pagination_keys = response.headers.keys.grep(/x-pagination-/i)
40
+ return if pagination_keys.empty?
41
+
42
+ @pagination = {}
43
+ pagination_keys.each do |k|
44
+ @pagination[k.gsub(/x-pagination-/i, '')] = response.headers[k]
52
45
  end
53
46
  end
54
47
 
48
+ # Faraday's :json middleware already parses responses with a JSON
49
+ # content type. Only try to parse bodies it left as strings.
55
50
  def parsed_response(response)
56
- if response.respond_to?(:data)
57
- response.data
58
- else
59
- begin
60
- json = JSON.parse(response.body)
61
- rescue => ex
62
- if @debug
63
- puts "ERROR PARSING JSON: #{ex.message}"
64
- puts ex.backtrace[0..5].join("\n")
65
- end
66
- response.body
67
- end
51
+ body = response.body
52
+ return body unless body.is_a?(String)
53
+
54
+ begin
55
+ JSON.parse(body)
56
+ rescue JSON::ParserError
57
+ body
68
58
  end
69
59
  end
70
60
 
@@ -85,7 +75,7 @@ module Adafruit
85
75
  end
86
76
  end
87
77
 
88
- def handle_post(url, data, options = {})
78
+ def handle_post(url, data)
89
79
  response = conn.post do |req|
90
80
  req.url url
91
81
  req.body = data
@@ -98,7 +88,7 @@ module Adafruit
98
88
  end
99
89
  end
100
90
 
101
- def handle_put(url, data, options = {})
91
+ def handle_put(url, data)
102
92
  response = conn.put do |req|
103
93
  req.url url
104
94
  req.body = data
@@ -111,17 +101,13 @@ module Adafruit
111
101
  end
112
102
  end
113
103
 
114
- def handle_delete(url, options = {})
104
+ def handle_delete(url, _data = nil)
115
105
  response = conn.delete do |req|
116
106
  req.url url
117
107
  end
118
108
 
119
109
  if response.status < 200 || response.status > 299
120
- if response.status === 404
121
- nil
122
- else
123
- raise Adafruit::IO::RequestError.new("DELETE error: #{ response.body }", response)
124
- end
110
+ raise Adafruit::IO::RequestError.new("DELETE error: #{ response.body }", response)
125
111
  else
126
112
  parsed_response response
127
113
  end
@@ -1,5 +1,5 @@
1
1
  module Adafruit
2
2
  module IO
3
- VERSION = "3.0.0"
3
+ VERSION = "4.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adafruit-io
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Cooper
8
8
  - Adam Bachman
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-10 00:00:00.000000000 Z
11
+ date: 2026-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -24,34 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.14'
27
- - !ruby/object:Gem::Dependency
28
- name: faraday-multipart
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.0'
41
- - !ruby/object:Gem::Dependency
42
- name: activesupport
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '8.0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '8.0'
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: mqtt
57
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +38,6 @@ dependencies:
66
38
  - - "~>"
67
39
  - !ruby/object:Gem::Version
68
40
  version: '0.7'
69
- - !ruby/object:Gem::Dependency
70
- name: bundler
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.7'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '2.7'
83
41
  - !ruby/object:Gem::Dependency
84
42
  name: rake
85
43
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +77,7 @@ files:
119
77
  - lib/adafruit/io/client/triggers.rb
120
78
  - lib/adafruit/io/client/user.rb
121
79
  - lib/adafruit/io/configurable.rb
80
+ - lib/adafruit/io/errors.rb
122
81
  - lib/adafruit/io/mqtt.rb
123
82
  - lib/adafruit/io/request_handler.rb
124
83
  - lib/adafruit/io/version.rb
@@ -133,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
92
  requirements:
134
93
  - - ">="
135
94
  - !ruby/object:Gem::Version
136
- version: '0'
95
+ version: '3.3'
137
96
  required_rubygems_version: !ruby/object:Gem::Requirement
138
97
  requirements:
139
98
  - - ">="