cocoro 0.1.0 → 0.2.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: 45dac1b85f589ac09c01682a1edc38cb0176736c09c7925a840f9dc2f1ccdbc9
4
- data.tar.gz: 9a184111ee00c3491226efbef049b925bbd7f2e2322cfa3bf3c70645fe157e65
3
+ metadata.gz: 0fc40cbd13bb06a8555da9d6939190793b159fd06ffe8d651cfa9cb5350bac62
4
+ data.tar.gz: 6042dfbba25e20371af33af4ef6942948c3c13271426fc3328ea831b4f13ac54
5
5
  SHA512:
6
- metadata.gz: abc7cf5682668a46f109acab88449a7266c6c2cd08f9503c7234b2c71760f1778c8eff6cb81eb7ebe5b074d17f2da256ece113e2e4ee2e9f9864157f715e9152
7
- data.tar.gz: 834021cdc1a98adeb9156961f2d36dc1098572dee7a468b62b4df0522897024a321802201758a7bd3fbfca6c7ccdb2e094987d2041ec0d406f6c4b560528e0c0
6
+ metadata.gz: 82d9251f028fc3d265a81764f72bd725558b7fb6ca98a87752070af04a74a5625f3330cef4d5c0199d4158be9eb37c58443e9530ac2ec90ee5e540ab043eaddc
7
+ data.tar.gz: e42598903d675c80ac8e934358f937a0242b271edb61dadab77dfdb9132448f15416282d3670c6888aad2933d200bf08f949c0e7b76a34bb4b076a3f633afb76
data/.rubocop.yml CHANGED
@@ -26,3 +26,4 @@ Metrics/ModuleLength:
26
26
  Metrics/BlockLength:
27
27
  Exclude:
28
28
  - spec/**/*_spec.rb
29
+ - cocoro.gemspec
data/Gemfile.lock CHANGED
@@ -83,6 +83,7 @@ GEM
83
83
 
84
84
  PLATFORMS
85
85
  x86_64-darwin-20
86
+ x86_64-linux
86
87
 
87
88
  DEPENDENCIES
88
89
  cocoro!
data/lib/cocoro/client.rb CHANGED
@@ -27,6 +27,8 @@ module Cocoro
27
27
  DEFAULT_RESULT_CHECK_INTERVAL = 0.7 # seconds
28
28
  DEFAULT_RESULT_CHECK_MAX_ATTEMPTS = 20
29
29
 
30
+ attr_accessor :logger
31
+
30
32
  def initialize(app_secret:, terminal_app_id_key:, logger: nil)
31
33
  @app_secret = app_secret
32
34
  @terminal_app_id_key = terminal_app_id_key
@@ -56,25 +58,17 @@ module Cocoro
56
58
  body,
57
59
  {}
58
60
  )
61
+ rescue Faraday::Error
62
+ raise Cocoro::ServerError
59
63
  end
60
64
 
61
65
  def devices
62
- response = @client.get(
63
- "setting/boxInfo?appSecret=#{CGI.escape(@app_secret)}&mode=other"
64
- )
65
- json = response.body
66
- json["box"].flat_map do |box|
67
- box["echonetData"].map do |data|
68
- Cocoro::Device.new(
69
- client: self,
70
- box_id: box["boxId"],
71
- device_id: data["deviceId"],
72
- echonet_node: data["echonetNode"],
73
- echonet_object: data["echonetObject"],
74
- name: data["labelData"]["name"]
75
- )
76
- end
66
+ response = handle_server_errors do
67
+ @client.get(
68
+ "setting/boxInfo?appSecret=#{CGI.escape(@app_secret)}&mode=other"
69
+ )
77
70
  end
71
+ Cocoro::Device.parse_box_info(response.body["box"], self)
78
72
  end
79
73
 
80
74
  def device_status(device:)
@@ -84,9 +78,11 @@ module Cocoro
84
78
  echonetNode: device.echonet_node,
85
79
  echonetObject: device.echonet_object
86
80
  }.map { |k, v| [k, CGI.escape(v)].join("=") }
87
- response = @client.get(
88
- "control/deviceStatus?#{query_params.join("&")}"
89
- )
81
+ response = handle_server_errors do
82
+ @client.get(
83
+ "control/deviceStatus?#{query_params.join("&")}"
84
+ )
85
+ end
90
86
  json = response.body
91
87
  Cocoro::Status.new(json["deviceStatus"]["status"])
92
88
  end
@@ -118,17 +114,19 @@ module Cocoro
118
114
  appSecret: @app_secret,
119
115
  boxId: device.box_id
120
116
  }.map { |k, v| [k, CGI.escape(v)].join("=") }
121
- response = @client.post(
122
- "control/deviceControl?#{query_params.join("&")}",
123
- controlList: [
124
- {
125
- deviceId: device.device_id,
126
- echonetNode: device.echonet_node,
127
- echonetObject: device.echonet_object,
128
- status: changes
129
- }
130
- ]
131
- )
117
+ response = handle_server_errors do
118
+ @client.post(
119
+ "control/deviceControl?#{query_params.join("&")}",
120
+ controlList: [
121
+ {
122
+ deviceId: device.device_id,
123
+ echonetNode: device.echonet_node,
124
+ echonetObject: device.echonet_object,
125
+ status: changes
126
+ }
127
+ ]
128
+ )
129
+ end
132
130
  response.body["controlList"].first["id"]
133
131
  end
134
132
 
@@ -137,15 +135,25 @@ module Cocoro
137
135
  appSecret: @app_secret,
138
136
  boxId: device.box_id
139
137
  }.map { |k, v| [k, CGI.escape(v)].join("=") }
140
- response = @client.post(
141
- "control/controlResult?#{query_params.join("&")}",
142
- resultList: [{ id: request_id }]
143
- )
138
+ response = handle_server_errors do
139
+ @client.post(
140
+ "control/controlResult?#{query_params.join("&")}",
141
+ resultList: [{ id: request_id }]
142
+ )
143
+ end
144
144
  result = response.body["resultList"].first
145
145
  @logger.info("Status: #{result["status"]}")
146
146
  raise Cocoro::Error, "Error code: #{result["errorCode"]}" if result["status"] == "error"
147
147
 
148
148
  result
149
149
  end
150
+
151
+ def handle_server_errors(&block)
152
+ block.call
153
+ rescue Faraday::UnauthorizedError, Faraday::ForbiddenError
154
+ raise Cocoro::AuthError
155
+ rescue Faraday::Error
156
+ raise Cocoro::ServerError
157
+ end
150
158
  end
151
159
  end
data/lib/cocoro/device.rb CHANGED
@@ -11,8 +11,29 @@ module Cocoro
11
11
  :echonet_node,
12
12
  :echonet_object,
13
13
  :name,
14
+ :type,
15
+ :maker,
16
+ :model,
14
17
  keyword_init: true
15
18
  ) do
19
+ def self.parse_box_info(box_info, client)
20
+ box_info.flat_map do |box|
21
+ box["echonetData"].map do |data|
22
+ new(
23
+ client: client,
24
+ box_id: box["boxId"],
25
+ device_id: data["deviceId"],
26
+ echonet_node: data["echonetNode"],
27
+ echonet_object: data["echonetObject"],
28
+ name: data["labelData"]["name"],
29
+ type: data["labelData"]["deviceType"],
30
+ maker: data["maker"],
31
+ model: data["model"]
32
+ )
33
+ end
34
+ end
35
+ end
36
+
16
37
  def status
17
38
  @status || fetch_status!
18
39
  end
data/lib/cocoro/error.rb CHANGED
@@ -1,6 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cocoro
4
+ # Base error class
4
5
  class Error < StandardError
5
6
  end
7
+
8
+ # Any non-200 response from the API
9
+ #
10
+ # That includes 400 responses which seems to be happening
11
+ # occasionally without any fault on the client side.
12
+ class ServerError < Cocoro::Error
13
+ end
14
+
15
+ # 401 or 403 error
16
+ class AuthError < Cocoro::ServerError
17
+ end
6
18
  end
data/lib/cocoro/status.rb CHANGED
@@ -9,23 +9,21 @@ module Cocoro
9
9
  temperature: ["F1", 4, 1], # °C
10
10
  humidity: ["F1", 5, 1], # %
11
11
  total_air_cleaned: ["F1", 22, 4], # m^3
12
- pm25: ["F1", 28, 2], # ug/m^3 : sometimes weird values because of the first byte
13
- f2unknown1: ["F2", 1, 1],
14
- smell: ["F2", 15, 1], # 0/33/66/100 (100=dirty)
12
+ pm25: ["F1", 28, 2], # ug/m^3, only last 9 bits are important
13
+ odor: ["F2", 15, 1], # 0/33/66/100 (100=dirty)
15
14
  dust: ["F2", 16, 1], # 0/25/50/75/100 (100=dirty)
16
- overall_cleanliness: ["F2", 18, 1], # 0/25/50/75/100 (100=dirty)
17
- f2unknown19: ["F2", 19, 1],
15
+ overall_dirtiness: ["F2", 18, 1], # 0/25/50/75/100 (100=dirty)
18
16
  enough_water: ["F2", 20, 1],
19
17
  light_detected: ["F2", 21, 1],
20
18
  air_volume: ["F3", 5, 1],
21
19
  power_on: ["F3", 14, 1],
22
- humidifier_on: ["F3", 16, 1],
23
- f3unknown20: ["F3", 20, 1]
20
+ humidifier_on: ["F3", 16, 1]
24
21
  }.freeze
25
22
  VALUES = {
26
23
  enough_water: { 0 => false, 255 => true },
27
24
  light_detected: { 0 => false, 255 => true },
28
25
  air_volume: {
26
+ 0 => nil,
29
27
  16 => "auto",
30
28
  17 => "night",
31
29
  19 => "pollen",
@@ -41,7 +39,7 @@ module Cocoro
41
39
 
42
40
  BOOLEAN_FIELDS = %i[enough_water light_detected power_on humidifier_on].freeze
43
41
  NON_BOOLEAN_FIELDS = %i[
44
- temperature humidity total_air_cleaned pm25 smell dust overall_cleanliness air_volume
42
+ temperature humidity total_air_cleaned pm25 odor dust overall_dirtiness air_volume
45
43
  ].freeze
46
44
 
47
45
  def initialize(array_of_status_data)
@@ -56,12 +54,9 @@ module Cocoro
56
54
  define_method(field) { read_value(field) }
57
55
  end
58
56
 
59
- # Get other data that we're not sure what it means, but could be useful for debugging
60
- def unknowns
61
- LOCATIONS
62
- .keys
63
- .select { |key| key.to_s =~ /unknown/ }
64
- .map { |key| [key, read_value(key)] }
57
+ def to_h
58
+ (BOOLEAN_FIELDS + NON_BOOLEAN_FIELDS)
59
+ .map { |f| [f, read_value(f)] }
65
60
  .to_h
66
61
  .merge(
67
62
  f1: read_binary_status("F1"),
@@ -70,13 +65,6 @@ module Cocoro
70
65
  )
71
66
  end
72
67
 
73
- def to_h
74
- (BOOLEAN_FIELDS + NON_BOOLEAN_FIELDS)
75
- .map { |f| [f, read_value(f)] }
76
- .to_h
77
- .merge(unknowns)
78
- end
79
-
80
68
  protected
81
69
 
82
70
  def read_value(name)
@@ -87,6 +75,8 @@ module Cocoro
87
75
  number = hex_code[(byte_offset - 1) * 2, byte_length * 2].to_i(16)
88
76
  if VALUES[name]&.key?(number)
89
77
  VALUES[name][number]
78
+ elsif name == :pm25
79
+ number & ((2**9) - 1) # last 9 bits only
90
80
  else
91
81
  number
92
82
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cocoro
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomasz Szczęśniak-Szlagowski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-06 00:00:00.000000000 Z
11
+ date: 2022-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -159,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
159
  - !ruby/object:Gem::Version
160
160
  version: '0'
161
161
  requirements: []
162
- rubygems_version: 3.2.15
162
+ rubygems_version: 3.1.6
163
163
  signing_key:
164
164
  specification_version: 4
165
165
  summary: An unofficial Cocoro Air client