somfy_sdn 2.4.1 → 2.5.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.
@@ -2,9 +2,13 @@
2
2
 
3
3
  module SDN
4
4
  class Message
5
+ # Command that resets a motor's persisted settings.
5
6
  class SetFactoryDefault < Message
7
+ # (see Ack::MSG)
6
8
  MSG = 0x1f
9
+ # (see Ack::PARAMS_LENGTH)
7
10
  PARAMS_LENGTH = 1
11
+ # Mapping from symbolic reset scopes to SDN parameter values.
8
12
  RESET = { all_settings: 0x00,
9
13
  group_addresses: 0x01,
10
14
  limits: 0x11,
@@ -13,14 +17,25 @@ module SDN
13
17
  ips: 0x15,
14
18
  locks: 0x17 }.freeze
15
19
 
20
+ # @!attribute [rw] reset
21
+ #
22
+ # Requested reset scope.
23
+ #
24
+ # @return [:all_settings, :group_addresses, :limits, :rotation, :rolling_speed, :ips, :locks]
16
25
  attr_reader :reset
17
26
 
27
+ # Creates a factory reset command.
28
+ #
29
+ # @param dest [(Integer, Integer, Integer), nil] destination address
30
+ # @param reset [:all_settings, :group_addresses, :limits, :rotation, :rolling_speed, :ips, :locks] reset scope
31
+ # @param kwargs [Hash] additional message options
18
32
  def initialize(dest = nil, reset = :all_settings, **kwargs)
19
33
  kwargs[:dest] ||= dest
20
34
  super(**kwargs)
21
35
  self.reset = reset
22
36
  end
23
37
 
38
+ # (see Message#parse)
24
39
  def parse(params)
25
40
  super
26
41
  self.reset = RESET.invert[to_number(params)]
@@ -35,18 +50,37 @@ module SDN
35
50
  @reset = value
36
51
  end
37
52
 
53
+ # (see Message#params)
38
54
  def params
39
55
  transform_param(RESET[reset])
40
56
  end
41
57
  end
42
58
 
59
+ # Command that assigns a motor to a group slot.
43
60
  class SetGroupAddr < Message
61
+ # (see Ack::MSG)
44
62
  MSG = 0x51
63
+ # (see Ack::PARAMS_LENGTH)
45
64
  PARAMS_LENGTH = 4
46
65
 
66
+ # @!attribute [rw] group_address
67
+ #
68
+ # @return [(Integer, Integer, Integer), nil]
47
69
  attr_accessor :group_address
70
+
71
+ # @!attribute [rw] group_index
72
+ #
73
+ # Group slot to assign the address to in the range 1..16.
74
+ #
75
+ # @return [Integer]
48
76
  attr_reader :group_index
49
77
 
78
+ # Creates a group assignment command.
79
+ #
80
+ # @param dest [(Integer, Integer, Integer), nil] destination address
81
+ # @param group_index [Integer] group slot
82
+ # @param group_address [(Integer, Integer, Integer), nil] group address
83
+ # @param kwargs [Hash] additional message options
50
84
  def initialize(dest = nil, group_index = 1, group_address = nil, **kwargs)
51
85
  kwargs[:dest] ||= dest
52
86
  super(**kwargs)
@@ -54,6 +88,7 @@ module SDN
54
88
  self.group_address = group_address
55
89
  end
56
90
 
91
+ # (see Message#parse)
57
92
  def parse(params)
58
93
  super
59
94
  self.group_index = to_number(params[0]) + 1
@@ -66,28 +101,43 @@ module SDN
66
101
  @group_index = value
67
102
  end
68
103
 
104
+ # (see Message#params)
69
105
  def params
70
106
  transform_param(group_index - 1) + transform_param(group_address || [0, 0, 0])
71
107
  end
72
108
 
109
+ # (see Message#class_inspect)
73
110
  def class_inspect
74
111
  ", group_index=#{group_index.inspect}, group_address=#{group_address ? print_address(group_address) : "nil"}"
75
112
  end
76
113
  end
77
114
 
115
+ # Command that sets a motor's rotation direction.
78
116
  class SetMotorDirection < Message
117
+ # (see Ack::MSG)
79
118
  MSG = 0x12
119
+ # (see Ack::PARAMS_LENGTH)
80
120
  PARAMS_LENGTH = 1
121
+ # Mapping from symbolic directions to SDN parameter values.
81
122
  DIRECTION = { standard: 0x00, reversed: 0x01 }.freeze
82
123
 
124
+ # @!attribute [rw] direction
125
+ #
126
+ # @return [:standard, :reversed]
83
127
  attr_reader :direction
84
128
 
129
+ # Creates a motor direction command.
130
+ #
131
+ # @param dest [(Integer, Integer, Integer), nil] destination address
132
+ # @param direction [:standard, :reversed] rotation direction
133
+ # @param kwargs [Hash] additional message options
85
134
  def initialize(dest = nil, direction = :standard, **kwargs)
86
135
  kwargs[:dest] ||= dest
87
136
  super(**kwargs)
88
137
  self.direction = direction
89
138
  end
90
139
 
140
+ # (see Message#parse)
91
141
  def parse(params)
92
142
  super
93
143
  self.direction = DIRECTION.invert[to_number(params[0])]
@@ -99,23 +149,52 @@ module SDN
99
149
  @direction = value
100
150
  end
101
151
 
152
+ # (see Message#params)
102
153
  def params
103
154
  transform_param(DIRECTION[direction])
104
155
  end
105
156
  end
106
157
 
158
+ # Command that stores, deletes, or distributes intermediate positions.
107
159
  class SetMotorIP < Message
160
+ # (see Ack::MSG)
108
161
  MSG = 0x15
162
+ # (see Ack::PARAMS_LENGTH)
109
163
  PARAMS_LENGTH = 4
110
164
  # for distribute, value is how many IPs to distribute over
165
+ # Mapping from symbolic write modes to SDN parameter values.
111
166
  TYPE = { delete: 0x00,
112
167
  current_position: 0x01,
113
168
  position_pulses: 0x02,
114
169
  position_percent: 0x03,
115
170
  distribute: 0x04 }.freeze
116
171
 
117
- attr_reader :type, :ip, :value
118
-
172
+ # @!attribute [rw] type
173
+ #
174
+ # Requested intermediate-position write mode.
175
+ #
176
+ # @return [:delete, :current_position, :position_pulses, :position_percent, :distribute]
177
+ attr_reader :type
178
+
179
+ # @!attribute [rw] ip
180
+ #
181
+ # Requested intermediate-position slot in the range 1..16.
182
+ #
183
+ # @return [Integer, nil]
184
+ attr_reader :ip
185
+
186
+ # @!attribute [rw] value
187
+ #
188
+ # @return [Integer, nil]
189
+ attr_reader :value
190
+
191
+ # Creates an intermediate position write command.
192
+ #
193
+ # @param dest [(Integer, Integer, Integer), nil] destination address
194
+ # @param type [Symbol] IP write mode
195
+ # @param ip [Integer, nil] IP slot
196
+ # @param value [Integer, nil] IP value
197
+ # @param kwargs [Hash] additional message options
119
198
  def initialize(dest = nil, type = :delete, ip = nil, value = nil, **kwargs)
120
199
  kwargs[:dest] ||= dest
121
200
  super(**kwargs)
@@ -124,6 +203,7 @@ module SDN
124
203
  self.value = value
125
204
  end
126
205
 
206
+ # (see Message#parse)
127
207
  def parse(params)
128
208
  super
129
209
  self.type = TYPE.invert[to_number(params[0])]
@@ -143,7 +223,7 @@ module SDN
143
223
  end
144
224
 
145
225
  def ip=(value)
146
- raise ArgumentError, "ip must be in range 1..16 or nil" unless ip.nil? || (1..16).cover?(ip)
226
+ raise ArgumentError, "ip must be in range 1..16 or nil" unless value.nil? || (1..16).cover?(value)
147
227
 
148
228
  @ip = value
149
229
  end
@@ -152,19 +232,45 @@ module SDN
152
232
  @value = value&.& 0xffff
153
233
  end
154
234
 
235
+ # (see Message#params)
155
236
  def params
156
237
  transform_param(TYPE[type]) + transform_param(ip || 0) + from_number(value || 0, 2)
157
238
  end
158
239
  end
159
240
 
241
+ # Command that modifies a motor's travel limits.
160
242
  class SetMotorLimits < Message
243
+ # (see Ack::MSG)
161
244
  MSG = 0x11
245
+ # (see Ack::PARAMS_LENGTH)
162
246
  PARAMS_LENGTH = 4
247
+ # Mapping from symbolic limit write modes to SDN parameter values.
163
248
  TYPE = { delete: 0x00, current_position: 0x01, specified_position: 0x02, jog_ms: 0x04, jog_pulses: 0x05 }.freeze
249
+ # Mapping from symbolic limit targets to SDN parameter values.
164
250
  TARGET = { down: 0x00, up: 0x01 }.freeze
165
251
 
166
- attr_reader :type, :target, :value
167
-
252
+ # @!attribute [rw] type
253
+ #
254
+ # @return [:delete, :current_position, :specified_position, :jog_ms, :jog_pulses]
255
+ attr_reader :type
256
+
257
+ # @!attribute [rw] target
258
+ #
259
+ # @return [:up, :down]
260
+ attr_reader :target
261
+
262
+ # @!attribute [rw] value
263
+ #
264
+ # @return [Integer, nil]
265
+ attr_reader :value
266
+
267
+ # Creates a limit write command.
268
+ #
269
+ # @param dest [(Integer, Integer, Integer), nil] destination address
270
+ # @param type [:delete, :current_position, :specified_position, :jog_ms, :jog_pulses] limit write mode
271
+ # @param target [:up, :down] target limit
272
+ # @param value [Integer, nil]
273
+ # @param kwargs [Hash] additional message options
168
274
  def initialize(dest = nil, type = :delete, target = :up, value = nil, **kwargs)
169
275
  kwargs[:dest] ||= dest
170
276
  super(**kwargs)
@@ -173,6 +279,7 @@ module SDN
173
279
  self.value = value
174
280
  end
175
281
 
282
+ # (see Message#parse)
176
283
  def parse(params)
177
284
  super
178
285
  self.type = TYPE.invert[to_number(params[0])]
@@ -199,6 +306,7 @@ module SDN
199
306
  @value = value&.& 0xffff
200
307
  end
201
308
 
309
+ # (see Message#params)
202
310
  def params
203
311
  param = value || 0
204
312
  param /= 10 if target == :jog_ms
@@ -206,12 +314,35 @@ module SDN
206
314
  end
207
315
  end
208
316
 
317
+ # Command that updates a motor's rolling speeds.
209
318
  class SetMotorRollingSpeed < Message
319
+ # (see Ack::MSG)
210
320
  MSG = 0x13
321
+ # (see Ack::PARAMS_LENGTH)
211
322
  PARAMS_LENGTH = 3
212
323
 
213
- attr_accessor :up_speed, :down_speed, :slow_speed
214
-
324
+ # @!attribute [rw] up_speed
325
+ #
326
+ # @return [Integer, nil]
327
+ attr_accessor :up_speed
328
+
329
+ # @!attribute [rw] down_speed
330
+ #
331
+ # @return [Integer, nil]
332
+ attr_accessor :down_speed
333
+
334
+ # @!attribute [rw] slow_speed
335
+ #
336
+ # @return [Integer, nil]
337
+ attr_accessor :slow_speed
338
+
339
+ # Creates a rolling-speed write command.
340
+ #
341
+ # @param dest [(Integer, Integer, Integer), nil] destination address
342
+ # @param up_speed [Integer, nil] upward speed
343
+ # @param down_speed [Integer, nil] downward speed
344
+ # @param slow_speed [Integer, nil] slow speed
345
+ # @param kwargs [Hash] additional message options
215
346
  def initialize(dest = nil, up_speed: nil, down_speed: nil, slow_speed: nil, **kwargs)
216
347
  kwargs[:dest] ||= dest
217
348
  super(**kwargs)
@@ -220,6 +351,7 @@ module SDN
220
351
  self.slow_speed = slow_speed
221
352
  end
222
353
 
354
+ # (see Message#parse)
223
355
  def parse(params)
224
356
  super
225
357
  self.up_speed = to_number(params[0])
@@ -227,42 +359,68 @@ module SDN
227
359
  self.slow_speed = to_number(params[2])
228
360
  end
229
361
 
362
+ # (see Message#params)
230
363
  def params
231
364
  transform_param(up_speed || 0xff) + transform_param(down_speed || 0xff) + transform_param(slow_speed || 0xff)
232
365
  end
233
366
  end
234
367
 
368
+ # Command that applies or clears the network lock state.
235
369
  class SetNetworkLock < Message
370
+ # (see Ack::MSG)
236
371
  MSG = 0x16
237
372
 
238
- attr_accessor :locked, :priority
373
+ # @!attribute [rw] locked
374
+ #
375
+ # @return [true, false, nil]
376
+ attr_accessor :locked
377
+
378
+ # @!attribute [rw] priority
379
+ #
380
+ # @return [Integer, nil]
381
+ attr_accessor :priority
239
382
 
383
+ # (see Message#parse)
240
384
  def parse(params)
241
385
  self.locked = to_number(params[0]) == 1
242
386
  self.priority = to_number(params[1])
243
387
  end
244
388
 
389
+ # (see Message#params)
245
390
  def params
246
391
  transform_param(locked ? 1 : 0) + transform_param(priority)
247
392
  end
248
393
  end
249
394
 
395
+ # Command that writes a node's user-visible label.
250
396
  class SetNodeLabel < Message
397
+ # (see Ack::MSG)
251
398
  MSG = 0x55
399
+ # Maximum label length, in bytes
252
400
  MAX_LENGTH = 16
253
401
 
402
+ # @!attribute [rw] label
403
+ #
404
+ # @return [String]
254
405
  attr_accessor :label
255
406
 
407
+ # Creates a node label write command.
408
+ #
409
+ # @param dest [(Integer, Integer, Integer), nil] destination address
410
+ # @param label [String]
411
+ # @param kwargs [Hash] additional message options
256
412
  def initialize(dest = nil, label = "", **kwargs)
257
413
  kwargs[:dest] ||= dest
258
414
  super(**kwargs)
259
415
  self.label = label
260
416
  end
261
417
 
418
+ # (see Message#parse)
262
419
  def parse(params)
263
420
  self.label = to_string(params)
264
421
  end
265
422
 
423
+ # (see Message#params)
266
424
  def params
267
425
  from_string(label, self.class::MAX_LENGTH)
268
426
  end
data/lib/sdn/message.rb CHANGED
@@ -3,10 +3,13 @@
3
3
  require "sdn/message/helpers"
4
4
 
5
5
  module SDN
6
+ # Raised when a parsed frame is structurally valid but its payload does not match the target message type.
6
7
  class MalformedMessage < RuntimeError; end
7
8
 
9
+ # Base type for all SDN protocol frames and message-specific serializers/parsers.
8
10
  class Message
9
11
  class << self
12
+ # @!visibility private
10
13
  def inherited(klass)
11
14
  super
12
15
  return Message.inherited(klass) unless self == Message
@@ -15,6 +18,11 @@ module SDN
15
18
  (@subclasses ||= []) << klass
16
19
  end
17
20
 
21
+ # Determines whether a received message satisfies the expected response for this request type.
22
+ #
23
+ # @param message [SDN::Message] received message candidate
24
+ #
25
+ # @return [true, false]
18
26
  def expected_response?(message)
19
27
  if /::Get([A-Za-z]+)/.match?(name)
20
28
  message.class.name == name.sub("::Get", "::Post") # rubocop:disable Style/ClassEqualityComparison
@@ -23,6 +31,11 @@ module SDN
23
31
  end
24
32
  end
25
33
 
34
+ # Attempts to parse the first valid SDN message from a byte stream.
35
+ #
36
+ # @param data [<Integer>] raw bytes buffered from the transport
37
+ #
38
+ # @return [(SDN::Message, Integer)] parsed message and consumed byte count
26
39
  def parse(data)
27
40
  offset = -1
28
41
  msg = length = ack_requested = message_class = nil
@@ -58,7 +71,7 @@ module SDN
58
71
  src = transform_param(data.slice(offset + 3, 3))
59
72
  dest = transform_param(data.slice(offset + 6, 3))
60
73
  begin
61
- result = message_class.new(node_type: node_type, ack_requested: ack_requested, src: src, dest: dest)
74
+ result = message_class.new(node_type:, ack_requested:, src:, dest:)
62
75
  result.parse(data.slice(offset + 9, length - 11))
63
76
  result.msg = msg if message_class == UnknownMessage
64
77
  rescue ArgumentError => e
@@ -70,10 +83,13 @@ module SDN
70
83
 
71
84
  private
72
85
 
86
+ # Builds a lookup table from protocol opcode to message class.
87
+ #
88
+ # @return [{Integer => Class}]
73
89
  def message_map
74
90
  @message_map ||=
75
91
  @subclasses.each_with_object({}) do |klass, memo|
76
- next memo unless klass.constants(false).include?(:MSG)
92
+ next memo unless klass.const_defined?(:MSG, false)
77
93
 
78
94
  memo[klass.const_get(:MSG, false)] = klass
79
95
  end
@@ -83,8 +99,32 @@ module SDN
83
99
  include Helpers
84
100
  singleton_class.include Helpers
85
101
 
86
- attr_accessor :node_type, :ack_requested, :src, :dest
87
-
102
+ # Message sender node type.
103
+ #
104
+ # @return [Symbol, Integer]
105
+ attr_accessor :node_type
106
+
107
+ # Whether this message requests an acknowledgement.
108
+ #
109
+ # @return [true, false]
110
+ attr_accessor :ack_requested
111
+
112
+ # Source address for the message.
113
+ #
114
+ # @return [(Integer, Integer, Integer)]
115
+ attr_accessor :src
116
+
117
+ # Destination address for the message.
118
+ #
119
+ # @return [(Integer, Integer, Integer)]
120
+ attr_accessor :dest
121
+
122
+ # Builds a message envelope with optional addressing and acknowledgement behavior.
123
+ #
124
+ # @param node_type [Symbol, Integer, nil] originating node type
125
+ # @param ack_requested [true, false] whether the receiver should acknowledge the message
126
+ # @param src [(Integer, Integer, Integer), nil] source address bytes
127
+ # @param dest [(Integer, Integer, Integer), nil] destination address bytes
88
128
  def initialize(node_type: nil, ack_requested: false, src: nil, dest: nil)
89
129
  @node_type = node_type || 0
90
130
  @ack_requested = ack_requested
@@ -96,6 +136,13 @@ module SDN
96
136
  @dest = dest || [0, 0, 0]
97
137
  end
98
138
 
139
+ # Parses protocol-specific parameter bytes into this message instance.
140
+ #
141
+ # @param params [<Integer>] raw parameter bytes
142
+ #
143
+ # @return [void]
144
+ #
145
+ # @raise [SDN::MalformedMessage] when the parameter payload length is invalid
99
146
  def parse(params)
100
147
  return unless self.class.const_defined?(:PARAMS_LENGTH) && params.length != self.class.const_get(:PARAMS_LENGTH)
101
148
 
@@ -104,6 +151,9 @@ module SDN
104
151
  end}"
105
152
  end
106
153
 
154
+ # Serializes the message to a packed SDN frame.
155
+ #
156
+ # @return [String] binary protocol frame
107
157
  def serialize
108
158
  result = transform_param(node_type_to_number(node_type)) + transform_param(src) + transform_param(dest) + params
109
159
  length = result.length + 4
@@ -113,10 +163,12 @@ module SDN
113
163
  result.pack("C*")
114
164
  end
115
165
 
166
+ # @return [true, false]
116
167
  def ==(other)
117
168
  serialize == other.serialize
118
169
  end
119
170
 
171
+ # @return [String]
120
172
  def inspect
121
173
  format("#<%s @node_type=%s, @ack_requested=%s, @src=%s, @dest=%s%s>",
122
174
  self.class.name,
@@ -128,6 +180,11 @@ module SDN
128
180
  end
129
181
  alias_method :to_s, :inspect
130
182
 
183
+ private
184
+
185
+ # Returns the protocol-specific portion of the inspection string.
186
+ #
187
+ # @return [String, nil]
131
188
  def class_inspect
132
189
  ivars = instance_variables - %i[@node_type @ack_requested @src @dest @params]
133
190
  return if ivars.empty?
@@ -137,22 +194,43 @@ module SDN
137
194
 
138
195
  protected
139
196
 
197
+ # Returns the protocol-specific payload bytes for this message.
198
+ #
199
+ # @return [<Integer>]
140
200
  def params
141
201
  []
142
202
  end
143
203
 
204
+ # Base class for request messages with no protocol-specific parameters.
144
205
  class SimpleRequest < Message
206
+ # Number of protocol parameter bytes expected
145
207
  PARAMS_LENGTH = 0
146
208
 
209
+ # Creates a simple request whose only payload is the destination address.
210
+ #
211
+ # @param dest [(Integer, Integer, Integer), nil] destination address
212
+ # @param kwargs [Hash] additional message options
147
213
  def initialize(dest = nil, **kwargs)
148
214
  kwargs[:dest] ||= dest
149
215
  super(**kwargs)
150
216
  end
151
217
  end
152
218
 
219
+ # Positive acknowledgement response for commands that requested one.
220
+ class Ack < SimpleRequest
221
+ # Protocol message number
222
+ MSG = 0x7f
223
+ # (see SimpleRequest::PARAMS_LENGTH)
224
+ PARAMS_LENGTH = 0
225
+ end
226
+
227
+ # Negative acknowledgement response emitted when a request cannot be fulfilled.
153
228
  class Nack < Message
229
+ # (see Ack::MSG)
154
230
  MSG = 0x6f
231
+ # (see Ack::PARAMS_LENGTH)
155
232
  PARAMS_LENGTH = 1
233
+ # Mapping from symbolic error names to SDN error codes.
156
234
  VALUES = { data_error: 0x01,
157
235
  unknown_message: 0x10,
158
236
  node_is_locked: 0x20,
@@ -165,38 +243,66 @@ module SDN
165
243
  # 37 not implemented? (get motor rolling speed)
166
244
  # 39 at limit? blocked?
167
245
 
168
- # presumed
246
+ # Parsed NACK error code as a symbolic name or raw integer.
247
+ #
248
+ # @return [Symbol, Integer, nil]
169
249
  attr_accessor :error_code
170
250
 
251
+ # Creates a negative acknowledgement message.
252
+ #
253
+ # @param dest [(Integer, Integer, Integer), nil] destination address
254
+ # @param error_code [Symbol, Integer, nil] protocol error code
255
+ # @param kwargs [Hash] additional message options
171
256
  def initialize(dest = nil, error_code = nil, **kwargs)
172
257
  kwargs[:dest] ||= dest
173
258
  super(**kwargs)
174
259
  self.error_code = error_code
175
260
  end
176
261
 
262
+ # Parses the negative acknowledgement error code.
263
+ #
264
+ # @param params [<Integer>] raw parameter bytes
177
265
  def parse(params)
178
266
  super
179
267
  error_code = to_number(params[0])
180
268
  self.error_code = VALUES.invert[error_code] || error_code
181
269
  end
182
- end
183
270
 
184
- class Ack < SimpleRequest
185
- MSG = 0x7f
186
- PARAMS_LENGTH = 0
271
+ # (see Message#params)
272
+ def params
273
+ transform_param(VALUES[error_code] || error_code)
274
+ end
187
275
  end
188
276
 
189
- # messages after this point were decoded from UAI+ communication and may be named wrong
277
+ # Fallback wrapper for frames whose opcode is unknown to the library.
278
+ #
279
+ # Messages after this point were decoded from UAI+ communication and may be named wrong.
190
280
  class UnknownMessage < Message
191
- attr_accessor :msg, :params
192
-
193
- def initialize(params = [], **kwargs)
194
- super(**kwargs)
281
+ # Unknown protocol opcode captured for this message.
282
+ #
283
+ # @return [Integer, nil]
284
+ attr_accessor :msg
285
+
286
+ # Raw undecoded parameter bytes for this message.
287
+ #
288
+ # @return [<Integer>, nil]
289
+ attr_accessor :params
290
+
291
+ # Creates a message wrapper for an unrecognized protocol opcode.
292
+ #
293
+ # @param params [<Integer>] raw unparsed parameter bytes
294
+ def initialize(params = [], **)
295
+ super(**)
195
296
  self.params = params
196
297
  end
197
298
 
198
299
  alias_method :parse, :params=
199
300
 
301
+ # Serializes an unknown message only when raw parameters are present.
302
+ #
303
+ # @return [String] binary protocol frame
304
+ #
305
+ # @raise [NotImplementedError] when parameters are unavailable
200
306
  def serialize
201
307
  # prevent serializing something we don't know
202
308
  raise NotImplementedError unless params
@@ -204,6 +310,7 @@ module SDN
204
310
  super
205
311
  end
206
312
 
313
+ # (see Message#class_inspect)
207
314
  def class_inspect
208
315
  result = if instance_of?(UnknownMessage)
209
316
  format(", @msg=%02xh", msg)
data/lib/sdn/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SDN
4
- VERSION = "2.4.1"
4
+ # Gem version string.
5
+ VERSION = "2.5.0"
5
6
  end
data/lib/sdn.rb CHANGED
@@ -5,18 +5,26 @@ require "logger"
5
5
  require "sdn/client"
6
6
  require "sdn/message"
7
7
 
8
+ # Top-level Somfy SDN module
8
9
  module SDN
10
+ # Broadcast destination address used for discovery and network-wide requests.
9
11
  BROADCAST_ADDRESS = [0xff, 0xff, 0xff].freeze
10
12
 
11
13
  class << self
12
- def logger=(logger)
13
- logger.datetime_format = "%Y-%m-%d %H:%M:%S.%L"
14
- logger.formatter = proc do |severity, datetime, _progname, msg|
15
- "#{datetime.strftime(logger.datetime_format)} " \
14
+ # @!attribute [rw] logger
15
+ #
16
+ # Sets a logger for use by this gem. If a logger is not set, a default logger that
17
+ # outputs to stdout with INFO level will be used.
18
+ #
19
+ # @return [Logger]
20
+ def logger=(value)
21
+ value.datetime_format = "%Y-%m-%d %H:%M:%S.%L"
22
+ value.formatter = proc do |severity, datetime, _progname, msg|
23
+ "#{datetime.strftime(value.datetime_format)} " \
16
24
  "[#{Process.pid}/#{Thread.current.object_id}] " \
17
25
  "#{severity}: #{msg}\n"
18
26
  end
19
- @logger = logger
27
+ @logger = value
20
28
  end
21
29
 
22
30
  def logger