awtrix_control 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f3ab9bbb11f50ef16f44802afcddacd4ed0735a3183c232e44629ebf180ed580
4
+ data.tar.gz: 37127243a83f3057591f1cf6c74054c25329a50badf1a4f166f0084c474f6c1c
5
+ SHA512:
6
+ metadata.gz: 4c96a251e9df3890cfa8bfb95448b246cd61f19f2ad0d9abb66af7eb893086cbd4d15363651f0697f7785b4d4c28ce02d4ad2112602178a073cc4164a5ef32c5
7
+ data.tar.gz: 78f63a8565721667c6b038948e1f081aa1da58b29af5b4b018f7025e586ac105fb478b9f5da75b094eb4ed444e4538e28734fc962f03022499f30af053a337bd
@@ -0,0 +1,471 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'request'
4
+
5
+ module AwtrixControl
6
+ class App
7
+ include AwtrixControl
8
+ attr_accessor :name, :payload
9
+
10
+ # Payload attributes with their types and camelCase keys:
11
+ ATTRIBUTES = {
12
+ text: { key: 'text' },
13
+ text_case: { key: 'textCase', default: 0 },
14
+ top_text: { key: 'topText', default: false },
15
+ text_offset: { key: 'textOffset', default: 0 },
16
+ center_text: { key: 'center', default: true },
17
+ text_color: { key: 'color' },
18
+ text_gradient: { key: 'gradient' },
19
+ blink_text: { key: 'blinkText' },
20
+ fade_text: { key: 'fadeText' },
21
+ background_color: { key: 'background' },
22
+ rainbow_effect: { key: 'rainbow' },
23
+ icon: { key: 'icon' },
24
+ push_icon: { key: 'pushIcon', default: 0 },
25
+ repeat_text: { key: 'repeat', default: -1 },
26
+ display_duration: { key: 'duration', default: 5 },
27
+ hold_notification: { key: 'hold', default: false },
28
+ sound: { key: 'sound' },
29
+ rtttl_sound: { key: 'rtttl' },
30
+ loop_sound: { key: 'loopSound', default: false },
31
+ bar_chart: { key: 'bar' },
32
+ line_chart: { key: 'line' },
33
+ auto_scale: { key: 'autoScale', default: true },
34
+ progress_bar: { key: 'progress', default: -1 },
35
+ progress_bar_color: { key: 'progressC', default: -1 },
36
+ progress_bar_background_color: { key: 'progressBC', default: -1 },
37
+ position: { key: 'pos' },
38
+ draw_commands: { key: 'draw' },
39
+ lifetime: { key: 'lifetime', default: 0 },
40
+ lifetime_mode: { key: 'lifetimeMode', default: 0 },
41
+ stack_notifications: { key: 'stack', default: true },
42
+ wakeup_display: { key: 'wakeup', default: false },
43
+ disable_scroll: { key: 'noScroll', default: false },
44
+ forward_clients: { key: 'clients' },
45
+ scroll_speed: { key: 'scrollSpeed', default: 100 },
46
+ background_effect: { key: 'effect' },
47
+ background_effect_settings: { key: 'effectSettings' },
48
+ save_app: { key: 'save' },
49
+ overlay_effect: { key: 'overlay' }
50
+ }.freeze
51
+
52
+ LIFETIME_MODE_OPTIONS = {
53
+ destroy: 0,
54
+ stale: 1
55
+ }.freeze
56
+
57
+ PUSH_ICON_OPTIONS = {
58
+ fixed: 0,
59
+ scroll_once: 1,
60
+ loop: 2,
61
+ }.freeze
62
+
63
+ TEXT_CASES = {
64
+ default: 0,
65
+ upcase: 1,
66
+ as_is: 2
67
+ }.freeze
68
+
69
+ # Initializes a new App instance.
70
+ #
71
+ # @param name [Symbol, String] the name of the app. Must be unique within the device, or the app will be overwritten
72
+ # @param payload [Hash, nil] the payload for the app
73
+ # @param device [Device, nil] the device to associate the app with
74
+ def initialize(name, payload: nil, device: nil)
75
+ @name = name
76
+ device << self if device
77
+ @payload = payload || default_payload
78
+ end
79
+
80
+ # Pushes the app to the associated device.
81
+ def push
82
+ return if @device.nil?
83
+ @device.push_app(self)
84
+ end
85
+
86
+ # Define getters for each attribute in ATTRIBUTES.
87
+ ATTRIBUTES.each do |method_name, options|
88
+ awtrix_attribute = options[:key]
89
+ define_method(method_name) do
90
+ payload[awtrix_attribute]
91
+ end
92
+ end
93
+
94
+ # Sets the autoscale attribute.
95
+ #
96
+ # @param value [Boolean] whether to autoscale the bar or line chart.
97
+ def autoscale=(value)
98
+ @payload[method_to_awtrix_key(:auto_scale)] = !!value
99
+ end
100
+
101
+ # Sets the background color.
102
+ #
103
+ # @param value [String, Symbol, Array<Integer>] the color to set the background to
104
+ # String: A hex color code
105
+ # Symbol: A color name. Must be a key in COLOR_MAPPINGS
106
+ # Array: An array of 3 integers representing the RGB values of the color
107
+ def background_color=(value)
108
+ @payload[method_to_awtrix_key(:background_color)] = normalize_color(value)
109
+ end
110
+
111
+ # Sets the background effect.
112
+ #
113
+ # @param value [String] the effect to apply to the background
114
+ def background_effect=(value)
115
+ @payload[method_to_awtrix_key(:background_effect)] = value
116
+ end
117
+
118
+ # Sets the background effect settings.
119
+ #
120
+ # @param value [Hash] the settings for the background effect
121
+ def background_effect_settings=(value)
122
+ @payload[method_to_awtrix_key(:background_effect_settings)] = value
123
+ end
124
+
125
+ # Sets the bar chart values.
126
+ #
127
+ # @param value [Array<Integer>] an array of integers to represent each bar
128
+ def bar_chart=(value)
129
+ @payload[method_to_awtrix_key(:bar_chart)] = value
130
+ end
131
+
132
+ # Sets the blink text frequency.
133
+ #
134
+ # @param value [Integer] the frequency (in ms) at which the text should blink
135
+ def blink_text=(value)
136
+ @payload[method_to_awtrix_key(:blink_text)] = value.to_i
137
+ end
138
+
139
+ # Gets the blink text frequency.
140
+ #
141
+ # @return [Integer] the frequency (in ms) at which the text should blink
142
+ def blink_text
143
+ @payload[method_to_awtrix_key(:blink_text)].to_i
144
+ end
145
+
146
+ # Sets whether to center the text.
147
+ #
148
+ # @param value [Boolean] whether to center the text
149
+ def center_text=(value)
150
+ @payload[method_to_awtrix_key(:center_text)] = value
151
+ end
152
+
153
+ # Returns the default payload.
154
+ #
155
+ # @return [Hash] the default payload
156
+ def default_payload
157
+ @default_payload ||=
158
+ ATTRIBUTES.each_with_object({}) do |(method_name, options), hash|
159
+ hash[options[:key]] = options[:default] if options.key?(:default)
160
+ end
161
+ end
162
+
163
+ # Deletes the app from the associated device.
164
+ def delete
165
+ @device&.delete_app(self)
166
+ end
167
+
168
+ # Gets the associated device.
169
+ #
170
+ # @return [Device, nil] the associated device
171
+ def device
172
+ @device
173
+ end
174
+
175
+ # Sets the associated device.
176
+ #
177
+ # @param new_device [Device] the new device to associate the app with
178
+ def device=(new_device)
179
+ @device.delete_app(self.name) if @device
180
+ @device = new_device
181
+
182
+ new_device << self
183
+ end
184
+
185
+ # Sets whether to disable text scrolling.
186
+ #
187
+ # @param value [Boolean] whether to disable text scrolling
188
+ def disable_scroll=(value)
189
+ @payload[method_to_awtrix_key(:disable_scroll)] = !!value
190
+ end
191
+
192
+ # Sets the display duration.
193
+ #
194
+ # @param value [Integer] for how long (in seconds) the notification should be shown
195
+ def display_duration=(value)
196
+ @payload[method_to_awtrix_key(:display_duration)] = value.to_i
197
+ end
198
+
199
+ # Sets the drawing commands.
200
+ #
201
+ # @param value [Array] array of drawing instructions
202
+ def draw_commands=(value)
203
+ @payload[method_to_awtrix_key(:draw_commands)] = value
204
+ end
205
+
206
+ # Sets the fade text frequency.
207
+ #
208
+ # @param value [Integer] the frequency (in ms) at which the text should fade in and out
209
+ def fade_text=(value)
210
+ @payload[method_to_awtrix_key(:fade_text)] = value.to_i
211
+ end
212
+
213
+ # Gets the fade text frequency.
214
+ #
215
+ # @return [Integer] the frequency (in ms) at which the text should fade in and out
216
+ def fade_text
217
+ @payload[method_to_awtrix_key(:fade_text)].to_i
218
+ end
219
+
220
+ # Sets the forward clients.
221
+ #
222
+ # @param value [Array<String>] an array of IP addresses of other devices to forward notifications to
223
+ def forward_clients=(value)
224
+ @payload[method_to_awtrix_key(:forward_clients)] = value
225
+ end
226
+
227
+ # Sets whether to hold the notification.
228
+ #
229
+ # @param value [Boolean] whether to hold the notification
230
+ def hold_notification=(value)
231
+ @payload[method_to_awtrix_key(:hold_notification)] = !!value
232
+ end
233
+
234
+ # Sets the icon.
235
+ #
236
+ # @param value [String] the icon ID or filename (without extension) to display on the app
237
+ def icon=(value)
238
+ @payload[method_to_awtrix_key(:icon)] = value
239
+ end
240
+
241
+ # Sets the lifetime.
242
+ #
243
+ # @param value [Integer] the time in seconds after which the app should be removed if no update is received
244
+ def lifetime=(value)
245
+ @payload[method_to_awtrix_key(:lifetime)] = value.to_i
246
+ end
247
+
248
+ # Sets the lifetime mode.
249
+ #
250
+ # @param value [Symbol, Integer] the lifetime mode to use
251
+ # Symbol options: :destroy, :stale
252
+ # Integer options: 0, 1
253
+ def lifetime_mode=(value)
254
+ @payload[method_to_awtrix_key(:lifetime_mode)] = LIFETIME_MODE_OPTIONS[value] || value
255
+ end
256
+
257
+ # Gets the lifetime mode.
258
+ #
259
+ # @return [Symbol, nil] the lifetime mode
260
+ def lifetime_mode
261
+ LIFETIME_MODE_OPTIONS.key(@payload[method_to_awtrix_key(:lifetime_mode)])
262
+ end
263
+
264
+ # Sets the line chart values.
265
+ #
266
+ # @param value [Array<Integer>] an array of integers to represent the line chart
267
+ def line_chart=(value)
268
+ @payload[method_to_awtrix_key(:line_chart)] = value
269
+ end
270
+
271
+ # Sets whether to loop the sound.
272
+ #
273
+ # @param value [Boolean] whether to loop the sound as long as the notification is shown
274
+ def loop_sound=(value)
275
+ @payload[method_to_awtrix_key(:loop_sound)] = !!value
276
+ end
277
+
278
+ # Sets the overlay effect.
279
+ #
280
+ # @param value [String] the effect to apply as an overlay
281
+ def overlay_effect=(value)
282
+ @payload[method_to_awtrix_key(:overlay_effect)] = value
283
+ end
284
+
285
+ # Sets the position of the app in the loop.
286
+ #
287
+ # @param value [Integer] the position of the app in the loop (starting at 0)
288
+ def position=(value)
289
+ @payload[method_to_awtrix_key(:position)] = value
290
+ end
291
+
292
+ # Sets the progress bar value.
293
+ #
294
+ # @param value [Integer] a value between 0 and 100 to set the progress bar to
295
+ def progress_bar=(value)
296
+ @payload[method_to_awtrix_key(:progress_bar)] = value.to_i
297
+ end
298
+
299
+ # Sets the progress bar background color.
300
+ #
301
+ # @param value [String, Symbol, Array<Integer>] the color to set the progress bar background to
302
+ def progress_bar_background_color=(value)
303
+ @payload[method_to_awtrix_key(:progress_bar_background_color)] = normalize_color(value)
304
+ end
305
+
306
+ # Sets the progress bar color.
307
+ #
308
+ # @param value [String, Symbol, Array<Integer>] the color to set the progress bar to
309
+ def progress_bar_color=(value)
310
+ @payload[method_to_awtrix_key(:progress_bar_color)] = normalize_color(value)
311
+ end
312
+
313
+ # Sets the push icon behavior.
314
+ #
315
+ # @param value [Symbol, Integer] a symbol defining the push icon behavior:
316
+ # :fixed, :scroll_once, :loop
317
+ # Or an integer between 0 and 2 representing the above symbols
318
+ def push_icon=(value)
319
+ @payload[method_to_awtrix_key(:push_icon)] = PUSH_ICON_OPTIONS[value] || value
320
+ end
321
+
322
+ # Gets the push icon behavior.
323
+ #
324
+ # @return [Symbol, nil] the push icon behavior
325
+ def push_icon
326
+ PUSH_ICON_OPTIONS.key(@payload[method_to_awtrix_key(:push_icon)])
327
+ end
328
+
329
+ # Sets whether to enable the rainbow effect.
330
+ #
331
+ # @param value [Boolean] whether to enable the rainbow effect
332
+ def rainbow_effect=(value)
333
+ @payload[method_to_awtrix_key(:rainbow_effect)] = !!value
334
+ end
335
+
336
+ # Sets the repeat text value.
337
+ #
338
+ # @param value [Integer] the number of times to repeat the text
339
+ def repeat_text=(value)
340
+ @payload[method_to_awtrix_key(:repeat_text)] = value.to_i
341
+ end
342
+
343
+ # Sets the RTTTL sound.
344
+ #
345
+ # @param value [String] a RTTTL string to play as a sound
346
+ def rtttl_sound=(value)
347
+ @payload[method_to_awtrix_key(:rtttl_sound)] = value
348
+ end
349
+
350
+ # Sets whether to save the app.
351
+ #
352
+ # @param value [Boolean] whether to save the app into flash memory
353
+ def save_app=(value)
354
+ @payload[method_to_awtrix_key(:save_app)] = !!value
355
+ end
356
+
357
+ # Sets the scroll speed.
358
+ #
359
+ # @param value [Integer] the new scroll speed, as a percentage of the original scroll speed
360
+ def scroll_speed=(value)
361
+ @payload[method_to_awtrix_key(:scroll_speed)] = value.to_i
362
+ end
363
+
364
+ # Sets whether to stack notifications.
365
+ #
366
+ # @param value [Boolean] whether to stack the notification
367
+ def stack_notifications=(value)
368
+ @payload[method_to_awtrix_key(:stack_notifications)] = !!value
369
+ end
370
+
371
+ # Sets the sound.
372
+ #
373
+ # @param value [String] the filename of the RTTTL ringtone file or the 4-digit number of the MP3
374
+ def sound=(value)
375
+ @payload[method_to_awtrix_key(:sound)] = value
376
+ end
377
+
378
+ # Sets the text.
379
+ #
380
+ # @param value [String] the text to display
381
+ def text=(value)
382
+ @payload[method_to_awtrix_key(:text)] = value
383
+ end
384
+
385
+ # Sets the text case.
386
+ #
387
+ # @param value [Symbol, Integer] the text case to use
388
+ # Symbol options: :default, :upcase, :as_is
389
+ # Integer options: 0, 1, 2
390
+ def text_case=(value)
391
+ @payload[method_to_awtrix_key(:text_case)] = TEXT_CASES[value] || value
392
+ end
393
+
394
+ # Gets the text case.
395
+ #
396
+ # @return [Symbol, nil] the text case
397
+ def text_case
398
+ TEXT_CASES.key(@payload[method_to_awtrix_key(:text_case)])
399
+ end
400
+
401
+ # Sets the text color.
402
+ #
403
+ # @param value [String, Symbol, Array<Integer>] the color to set the text to
404
+ # String: A hex color code
405
+ # Symbol: A color name. Must be a key in COLOR_MAPPINGS
406
+ # Array: An array of 3 integers representing the RGB values of the color
407
+ def text_color=(value)
408
+ @payload[method_to_awtrix_key(:text_color)] = normalize_color(value)
409
+ end
410
+
411
+ # Sets the text gradient.
412
+ #
413
+ # @param gradient [Hash] a hash with keys :from and :to, each with a color value
414
+ # String: A hex color code
415
+ # Symbol: A color name. Must be a key in COLOR_MAPPINGS
416
+ # Array: An array of 3 integers representing the RGB values of the color
417
+ def text_gradient=(gradient)
418
+ from = normalize_color(gradient[:from])
419
+ to = normalize_color(gradient[:to])
420
+ @payload[method_to_awtrix_key(:text_gradient)] = [from, to]
421
+ end
422
+
423
+ # Gets the text gradient.
424
+ #
425
+ # @return [Hash] a hash with keys :from and :to, each with a color value
426
+ def text_gradient
427
+ raw_gradient = @payload[method_to_awtrix_key(:text_gradient)]
428
+ return { from: nil, to: nil } if raw_gradient.nil?
429
+ {
430
+ from: raw_gradient[0],
431
+ to: raw_gradient[1]
432
+ }
433
+ end
434
+
435
+ # Sets the text offset.
436
+ #
437
+ # @param value [Integer] the offset for the x position of a starting text
438
+ def text_offset=(value)
439
+ @payload[method_to_awtrix_key(:text_offset)] = value
440
+ end
441
+
442
+ # Sets whether to draw the text on top.
443
+ #
444
+ # @param value [Boolean] whether to draw the text on top
445
+ def top_text=(value)
446
+ @payload[method_to_awtrix_key(:top_text)] = value
447
+ end
448
+
449
+ # Sets the text case to uppercase.
450
+ def upcase
451
+ @payload[method_to_awtrix_key(:text_case)] = 1
452
+ end
453
+
454
+ # Sets whether to wake up the display for the notification.
455
+ #
456
+ # @param value [Boolean] whether to wake up the display for the notification
457
+ def wakeup_display=(value)
458
+ @payload[method_to_awtrix_key(:wakeup_display)] = !!value
459
+ end
460
+
461
+ private
462
+
463
+ # Converts a method name to its corresponding Awtrix key.
464
+ #
465
+ # @param method_name [Symbol] the method name
466
+ # @return [String] the corresponding Awtrix key
467
+ def method_to_awtrix_key(method_name)
468
+ ATTRIBUTES[method_name][:key]
469
+ end
470
+ end
471
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'request'
4
+
5
+ module AwtrixControl
6
+ # The Device class is used to manage the apps on an Awtrix device.
7
+ # The apps are stored in a registry within the device, so you can refer to them by name.
8
+ # Note that there is no synchronization between devices or between device and device.
9
+ # E.g. If you instantiate 2 devices for the same device, they will not be aware of each other and apps could collide,
10
+ # or race conditions could occur.
11
+ class Device
12
+ include AwtrixControl
13
+
14
+ INDICATOR_INDEX = { top: 1, center: 2, bottom: 3 }.freeze
15
+
16
+ attr_reader :apps, :host
17
+
18
+ # Initializes a new Device instance.
19
+ #
20
+ # @param host [String] the IP address or hostname of the Awtrix device
21
+ def initialize(host)
22
+ @host = host
23
+ @apps = {}
24
+ end
25
+
26
+ # Adds an app to the device.
27
+ #
28
+ # @param app [App] the app to add
29
+ # @return [App] the added app
30
+ def <<(app)
31
+ @apps[app.name] = app
32
+ app.device = self unless app.device == self
33
+ app
34
+ end
35
+
36
+ # Retrieves an app by name.
37
+ #
38
+ # @param name [String] the name of the app
39
+ # @return [App, nil] the app if found, otherwise nil
40
+ def [](name)
41
+ @apps[name]
42
+ end
43
+
44
+ # Retrieves the effects from the device.
45
+ #
46
+ # @return [Hash] the effects
47
+ def effects
48
+ get('effects')
49
+ end
50
+
51
+ # Sets the indicator on the device.
52
+ #
53
+ # @param location [Symbol] The location of the indicator to render.
54
+ # Must be a key in INDICATOR_INDEX (:top, :center, :bottom)
55
+ # @param color [String, Array, Symbol] the color to set the indicator to.
56
+ # String: A HEX string representing the color
57
+ # Array: An array of 3 integers representing the RGB values of the color
58
+ # Symbol: A symbol representing the color. Must be a key in COLOR_MAPPINGS
59
+ # @param effect [Symbol, nil] the effect to apply (e.g., :blink, :pulse)
60
+ # @param frequency [Integer, nil] the frequency of the effect
61
+ def indicator(location, color = :white, effect: nil, frequency: nil)
62
+ payload = {}
63
+ payload[:color] = AwtrixControl::COLOR_MAPPINGS[color] || color
64
+ payload[:blink] = frequency || 500 if effect == :blink
65
+ payload[:fade] = frequency || 2000 if effect == :pulse
66
+ index = INDICATOR_INDEX[location]
67
+ post("indicator#{index.to_i}", payload)
68
+ end
69
+
70
+ # Retrieves the current loop state.
71
+ #
72
+ # @return [Hash] the current loop state, as a Hash of apps and their current index.
73
+ # @example
74
+ # device.loop
75
+ # { "Hello" => 1, "Time" => 0, "World" => 2 }
76
+ def loop
77
+ JSON.parse(get('loop'))
78
+ end
79
+
80
+ # Creates a new app and adds it to the device.
81
+ #
82
+ # @param name [String] the name of the app
83
+ # @param payload [Hash] additional payload for the app
84
+ # @return [App] the created app
85
+ def new_app(name, **payload)
86
+ app = payload.empty? ? App.new(name, device: self) : App.new(name, payload:, device: self)
87
+ self << app
88
+ app
89
+ end
90
+
91
+ # Sends a notification to the device.
92
+ #
93
+ # @param text [String] the notification text
94
+ # @param payload [Hash] additional payload for the notification
95
+ def notify(text, **payload)
96
+ payload[:color] = normalize_color(payload[:color] || :white)
97
+ post('notify', { text: }.merge(payload))
98
+ end
99
+
100
+ # Sets the power state of the device.
101
+ #
102
+ # @param switch [Boolean] the power state to set
103
+ # Note that this only turns off the display, not the device itself
104
+ def power(switch)
105
+ post('power', { power: switch })
106
+ end
107
+
108
+ # Removes an indicator from the device.
109
+ #
110
+ # @param location [Symbol] the location of the indicator to remove
111
+ def remove_indicator(location)
112
+ indicator(location, :black)
113
+ end
114
+
115
+ # Removes all indicators from the device.
116
+ def remove_indicators
117
+ INDICATOR_INDEX.each_key { |location| remove_indicator(location) }
118
+ end
119
+
120
+ # Resets the device.
121
+ def reset
122
+ sleep(1)
123
+ end
124
+
125
+ # Plays an RTTTL string on the device.
126
+ #
127
+ # @param rtttl_string [String] the RTTTL string to play
128
+ def rtttl(rtttl_string)
129
+ post('rtttl', rtttl_string)
130
+ end
131
+
132
+ # Retrieves the screen state from the device.
133
+ #
134
+ # @return [Hash] the screen state
135
+ def screen
136
+ get('screen')
137
+ end
138
+
139
+ # Puts the device to sleep.
140
+ #
141
+ # @param seconds [Integer] the number of seconds to sleep
142
+ # If no seconds are provided, the device will sleep indefinitely
143
+ def sleep(seconds = 0)
144
+ payload = (seconds.to_i > 0 ? { sleep: seconds.to_i } : {})
145
+ post('sleep', **payload)
146
+ end
147
+
148
+ # Plays a sound on the device.
149
+ #
150
+ # @param name [String] the name of the sound to play
151
+ def sound(name)
152
+ post('sound', { sound: name })
153
+ end
154
+
155
+ # Retrieves the device statistics.
156
+ #
157
+ # @return [Hash] the device statistics
158
+ def stats
159
+ get('stats')
160
+ end
161
+
162
+ # Retrieves the transitions from the device.
163
+ #
164
+ # @return [Hash] the transitions
165
+ def transitions
166
+ get('transitions')
167
+ end
168
+
169
+ # Deletes an app from the device.
170
+ #
171
+ # @param app_name [String, Symbol] the app name to delete
172
+ def delete_app(app_name)
173
+ post('custom', {}, { name: app_name })
174
+ @apps.delete(app_name)
175
+ end
176
+
177
+ # Deletes all apps from the device.
178
+ def delete_all_apps
179
+ loop.each_key { |app_name| delete_app(app_name) }
180
+ @apps = {}
181
+ end
182
+
183
+ # Pushes an app to the device, or updates an existing one.
184
+ #
185
+ # @param app_name [Symbol, String] the app name to push
186
+ def push_app(app_name)
187
+ registered_app = @apps[app_name]
188
+ return unless registered_app
189
+
190
+ post('custom',
191
+ { name: registered_app.name }.merge(registered_app.payload),
192
+ { name: registered_app.name })
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module AwtrixControl
7
+ module Request
8
+ private
9
+
10
+ def get(path)
11
+ uri = uri(path)
12
+ http = Net::HTTP.new(uri.host, uri.port)
13
+ request = Net::HTTP::Get.new(uri)
14
+ response = http.request(request)
15
+ response.body
16
+ end
17
+
18
+ def post(path, payload = {}, query_params = {})
19
+ uri = uri(path, query_params)
20
+ http = Net::HTTP.new(uri.host, uri.port)
21
+ request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
22
+ request.body = payload.to_json
23
+ response = http.request(request)
24
+ response.body
25
+ end
26
+
27
+ def uri(path, query_params = {})
28
+ query_params = query_params.map { |k, v| "#{k}=#{v}" }.join('&')
29
+ query_params = "?#{query_params}" unless query_params.empty?
30
+ URI("http://#{host}/api/#{path}#{query_params}")
31
+ end
32
+ end
33
+ end