syncsign 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2ec8ce97ef1f4882420617de3310d74e2d4a3783a4f1922847c706c3eb04b13c
4
+ data.tar.gz: 0a867fa0debe259b37d347aff38800f9ae589a4e2afde253d69fbe2f2cab4bbe
5
+ SHA512:
6
+ metadata.gz: fc9cc2483763d6a35cee7d3c9370b2abe6774b5870321ec219ed02c26b61a0d60378c8a38149507bcef9e4cecbb6b88f9a4888e888732d7d47516d6597ab4d3b
7
+ data.tar.gz: 9bba6acf10f9b33d4a9d11065e12ae6c3d4270bc95e991e03651aace8dd0c52655fe07ea628f110572a0b58b6fce7ca51601dcf48d43cd30308b574b5b165de9
@@ -0,0 +1,38 @@
1
+ # SyncSign - Ruby interface to the SyncSign e-paper display system
2
+
3
+ ## Description
4
+
5
+ Ruby class/gem to access the [SyncSign](http://sync-sign.com) cloud service to display information on e-paper displays.
6
+
7
+ ## Features
8
+ * Display circles, lines, rectangles, QR codes, and text on the displays.
9
+ * Obtain information about associated hubs and displays.
10
+
11
+ ## TODO
12
+ * Support non-display nodes that connect to the SyncSign hub (like temperature or occupancy sensors)
13
+ * Support display-resident images (item type IMAGE)
14
+ * Support bitmap images from a URI (item type BITMAP\_URI)
15
+ * Support icons in text boxes
16
+
17
+ ## Use
18
+
19
+ Create a SyncSign Service instance using your API key (found in the SyncSign portal settings):
20
+
21
+ require 'syncsign'
22
+
23
+ signsvc = SyncSign::Service.new('<api key>')
24
+ node = signsvc.node('<node id>')
25
+ items = [
26
+ SyncSign::Widget::Rectangle.new(x: 8, y: 8, width: 208, height: 60, pen_width: 2),
27
+ SyncSign::Widget::Textbox.new(x: 16, y: 16, width: 192, height: 44, font: :roboto_slab, size: 24, align: :center, text: "Hello, World!")
28
+ ]
29
+ template = SyncSign::Template.new(items: items)
30
+ node.render(template: template)
31
+
32
+ ## Examples
33
+
34
+ Check out the examples/ folder for:
35
+ * account\_info.rb - Show information about the account associated with the provided API key.
36
+ * nodes.rb - List all nodes on the system and information about them.
37
+ * render.rb - Render a sample screen to the given node.
38
+
@@ -0,0 +1,38 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ rescue LoadError
8
+ end
9
+
10
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
11
+ require "syncsign/version"
12
+ require "yard"
13
+
14
+ YARD::Rake::YardocTask.new do |t|
15
+ t.files = ['lib/**/*.rb']
16
+ t.options = %w(--markup-provider=redcarpet --markup=markdown --main=README.md)
17
+ end
18
+
19
+ desc "Builds the gem"
20
+ task :gem => :build
21
+ task :build => :yard do
22
+ system "gem build syncsign.gemspec"
23
+ Dir.mkdir("pkg") unless Dir.exists?("pkg")
24
+ system "mv syncsign-#{SyncSign::VERSION}.gem pkg/"
25
+ end
26
+
27
+ task :install => :build do
28
+ system "sudo gem install pkg/syncsign-#{SyncSign::VERSION}.gem"
29
+ end
30
+
31
+ desc "Release the gem - Gemcutter"
32
+ task :release => :build do
33
+ system "git tag -a v#{SyncSign::VERSION} -m 'Tagging #{SyncSign::VERSION}'"
34
+ system "git push --tags"
35
+ system "gem push pkg/syncsign-#{SyncSign::VERSION}.gem"
36
+ end
37
+
38
+ task :default => [:spec]
@@ -0,0 +1,9 @@
1
+ require 'net/http'
2
+
3
+ require 'syncsign/version.rb'
4
+ require 'syncsign/service.rb'
5
+ require 'syncsign/hub.rb'
6
+ require 'syncsign/node.rb'
7
+ require 'syncsign/node-display.rb'
8
+ require 'syncsign/template.rb'
9
+ require 'syncsign/widgets.rb'
@@ -0,0 +1,25 @@
1
+ module SyncSign
2
+ ##
3
+ # Object that represents a SyncSign hub.
4
+ class Hub
5
+ # @return [String] the serial number of the hub.
6
+ attr_reader :sn
7
+ # @return [String] the friendly name of the hub.
8
+ attr_reader :name
9
+
10
+ ##
11
+ # Initialize a new hub object (normally only called from Service#hubs)
12
+ def initialize(sn: null, name: null, service: null)
13
+ @sn = sn
14
+ @name = name
15
+ @service = service
16
+ end
17
+
18
+ ##
19
+ # Retrieve a collection of all +Node+ objects serviced by this hub.
20
+ def nodes
21
+ SyncSign::Node::parse_collection(service: @service, nodeinfo: @service.api_call(path: "/devices/#{@sn}/nodes"))
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,18 @@
1
+ module SyncSign
2
+ ##
3
+ # Object that represents a SyncSign display node.
4
+ class Display < Node
5
+ ##
6
+ # Render a template to this display.
7
+ # @param template [Template] Template to render to this display.
8
+ def render(template: nil)
9
+ @service.api_call(type: :post, path: "/nodes/#{@id}/renders", data: template.to_s)
10
+ end
11
+
12
+ ##
13
+ # Return true if the node can display a colour other than black and white.
14
+ def has_colour?
15
+ ['D29R', 'D75'].include? @model
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,73 @@
1
+ module SyncSign
2
+ ##
3
+ # Object that represents a SyncSign node.
4
+ # TODO: Split this up and add support for non-display nodes.
5
+ class Node
6
+ # @return [String] the Node ID of this node.
7
+ attr_reader :id
8
+ # @return [String] the friendly name of this node.
9
+ attr_reader :name
10
+ # @return [Integer] the current battery level of this node (0-100)
11
+ attr_reader :battery
12
+ # @return [Integer] the current signal level of this node (0-100)
13
+ attr_reader :signal
14
+ # @return [String] model of thid node.
15
+ attr_reader :model
16
+
17
+ ##
18
+ # Initialize a new Node object (normally only called from Hub#nodes or Service#nodes).
19
+ def initialize(service: nil, id: nil, name: nil, online: nil, battery: nil, signal: nil, model: nil)
20
+ @service = service
21
+ @id = id
22
+ @name = name
23
+ @online = online
24
+ @battery = battery
25
+ @signal = signal
26
+ @model = model
27
+ end
28
+
29
+ ##
30
+ # Return true if the node was online during the last information gathering.
31
+ def is_online?
32
+ @online
33
+ end
34
+
35
+ ##
36
+ # Parse a JSON description of a single node into a +Node+ object.
37
+ # Normally only called from Hub#nodes or Service#nodes.
38
+ # @api private
39
+ def self.parse(service: nil, nodeinfo: nil)
40
+ node_class = Node
41
+ case nodeinfo['type']
42
+ when 'DISPLAY'
43
+ node_class = Display
44
+ # TODO: support sensors and any other node types
45
+ end
46
+ node_class.new(
47
+ service: service,
48
+ id: nodeinfo['nodeId'],
49
+ name: nodeinfo['name'],
50
+ online: nodeinfo['onlined'],
51
+ battery: nodeinfo['batteryLevel'],
52
+ signal: nodeinfo['signalLevel'],
53
+ model: nodeinfo['model']
54
+ )
55
+ end
56
+
57
+ ##
58
+ # Parse JSON array of nodes into a collection of Node objects.
59
+ # @param service [SyncSign::Service] Instance of the SyncSign Service class.
60
+ # @param nodeinfo [String] Information about a collection of nodes,
61
+ # in JSON format.
62
+ # @return [Array] Array of Node objects.
63
+ # @api private
64
+ def self.parse_collection(service: nil, nodeinfo: nil)
65
+ nodes = []
66
+ nodeinfo.each do |node|
67
+ nodes.push Node::parse(service: service, nodeinfo: node)
68
+ end
69
+ p nodes
70
+ nodes
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,89 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ ##
5
+ # The SyncSign module contains everything needed to interface with the
6
+ # SyncSign cloud server and display information on their e-paper displays.
7
+ module SyncSign
8
+ ##
9
+ # Raised if an error occurs communicating with the SyncSign cloud service.
10
+ class APICallException < StandardError
11
+ end
12
+
13
+ ##
14
+ # Object that communicates with the SyncSign cloud service.
15
+ class Service
16
+ ##
17
+ # Set up a new connection to the SyncSign cloud service.
18
+ # @param apikey [String] the API key provided through the SyncSign portal.
19
+ def initialize(apikey: null)
20
+ @apikey = apikey
21
+ @baseurl = "https://api.sync-sign.com/v2/key/#{apikey}"
22
+ end
23
+
24
+ ##
25
+ # Retrieve an array of information about the SyncSign cloud service account
26
+ # associated with this object.
27
+ def account_info()
28
+ api_call()
29
+ end
30
+
31
+ ##
32
+ # Retrieve a collection of all +Hub+ objects registered under the account.
33
+ def hubs
34
+ hubs = []
35
+ hub_data = api_call(path: "/devices")
36
+ hub_data.each do |hub|
37
+ hubs.push Hub.new(
38
+ service: self,
39
+ sn: hub['sn'],
40
+ name: hub['info']['friendlyName']
41
+ )
42
+ end
43
+
44
+ hubs
45
+ end
46
+
47
+ ##
48
+ # Retrieve a collection of all +Node+ objects registered under the account.
49
+ def nodes()
50
+ Node::parse_collection(service: self, nodeinfo: api_call(path: "/nodes"))
51
+ end
52
+
53
+ ##
54
+ # Retrieve a single +Node+ object with the given id.
55
+ # @param id [String] Node ID to retrieve the object for.
56
+ def node(id)
57
+ Node::parse(service: self, nodeinfo: api_call(path: "/nodes/#{id}"))
58
+ end
59
+
60
+ ##
61
+ # Make a call to the SyncSign cloud service.
62
+ # @param type [Symbol] The HTTP method to use, either :get or :put.
63
+ # @param path [String] The path to make the API call to, minus the base path.
64
+ # @param data [String] The POST data to send with the API call.
65
+ # @api private
66
+ def api_call(type: :get, path: "", data: "")
67
+ apiurl = URI.parse("#{@baseurl}#{path}")
68
+ http_obj = Net::HTTP.new(apiurl.host, apiurl.port)
69
+ http_obj.use_ssl = true
70
+ response = nil
71
+ http_obj.start() do |http|
72
+ req = nil
73
+ if(type == :get) then
74
+ req = Net::HTTP::Get.new(apiurl.request_uri)
75
+ else
76
+ req = Net::HTTP::Post.new(apiurl.request_uri)
77
+ req.body = data
78
+ req['Content-Type'] = 'application/json'
79
+ end
80
+ response = http.request(req)
81
+ end
82
+ if(response.code.to_i != 200) then
83
+ raise APICallException, response.read_body
84
+ end
85
+ JSON.parse(response.read_body)['data']
86
+ end
87
+ end
88
+ end
89
+
@@ -0,0 +1,50 @@
1
+ require 'json'
2
+
3
+ module SyncSign
4
+ ##
5
+ # Object that represents a template that can be rendered onto a display.
6
+ # Contains +Widget+s which define the UI elements on the +Template+.
7
+ class Template
8
+ attr_accessor :bgcolour, :pollrate
9
+ attr_reader :items
10
+
11
+ ##
12
+ # Initialize a new template and optionally add items to it.
13
+ # @param bgcolour [Symbol] Background colour, one of :black, :white, or :red.
14
+ # @param items [Array] List of Widgets to add to the template.
15
+ # @param pollrate [Integer] How often (in ms) the node should poll the hub
16
+ # for new information.
17
+ def initialize(bgcolour: :white, items: [], pollrate: 10000)
18
+ @bgcolour = bgcolour
19
+ @pollrate = pollrate
20
+
21
+ @items = []
22
+ items.each do |item|
23
+ self.+(item)
24
+ end
25
+ end
26
+
27
+ ##
28
+ # Add a new widget to the template.
29
+ # @param to_add [Widget] Widget to add to the template.
30
+ def +(to_add)
31
+ # TODO: make sure we only add widgets
32
+ @items.push to_add
33
+ end
34
+
35
+ ##
36
+ # Output this template as JSON in the format that the SyncSign service understands.
37
+ def to_s
38
+ background = {bgColor: @bgcolour.to_s.upcase}
39
+ items = @items.collect { |item| item.to_a }
40
+ options = {'pollRate': @pollrate}
41
+ {
42
+ layout: {
43
+ background: background,
44
+ items: items,
45
+ options: options
46
+ }
47
+ }.to_json
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ module SyncSign
2
+ # The version number of the SyncSign module.
3
+ VERSION = '0.2.0'
4
+ end
@@ -0,0 +1,323 @@
1
+ module SyncSign
2
+ ##
3
+ # Raised when UI elements are not properly aligned.
4
+ # Several UI elements must be aligned to a multiple of 8 or corruption will
5
+ # occur on the display.
6
+ class AlignmentException < StandardError
7
+ end
8
+
9
+ ##
10
+ # Widgets are UI elements that are placed onto a +Template+ for rendering.
11
+ class Widget
12
+ ##
13
+ # An item that contains only x/y coordinates. This can't be used on its own, only its
14
+ # superclasses can be added to templates.
15
+ class Item
16
+ # @return [Integer] horizontal position of the item.
17
+ attr_accessor :x
18
+ # @return [Integer] vertical position of the item.
19
+ attr_accessor :y
20
+
21
+ ##
22
+ # Initialize a new Item widget.
23
+ # @param x [Integer] The horizontal position of the item.
24
+ # @param y [Integer] The vertical position of the item.
25
+ def initialize(x: nil, y: nil)
26
+ @x = x
27
+ @y = y
28
+ end
29
+ end
30
+
31
+ ##
32
+ # A box that contains x/y coordinates, width and height, and colour information.
33
+ # This can't be used on its own, only its superclasses can be added to templates.
34
+ # You may be looking for +Rectangle+ if you want to draw rectangles.
35
+ class Box < Item
36
+ # @return [Integer] the width of the box.
37
+ attr_accessor :width
38
+ # @return [Integer] the height of the box.
39
+ attr_accessor :height
40
+ # @return [Symbol] the stroke or foreground colour of the box.
41
+ attr_accessor :colour
42
+ # @return [Symbol] the background colour of the box.
43
+ attr_accessor :bgcolour
44
+
45
+ def initialize(x: nil, y: nil, width: nil, height: nil, colour: :black, bgcolour: :white)
46
+ Widget::check_colours [colour, bgcolour]
47
+ @colour = colour
48
+ @bgcolour = bgcolour
49
+ @width = width
50
+ @height = height
51
+ super(x: x, y: y)
52
+ end
53
+ end
54
+
55
+ ##
56
+ # A widget that draws a rectangle.
57
+ class Rectangle < Box
58
+ attr_accessor :pen_width
59
+
60
+ ##
61
+ # Initialize a new rectangle widget.
62
+ # @param x [Integer] horizontal position of the left side of the rectangle.
63
+ # @param y [Integer] vertical position of the top of the rectangle.
64
+ # @param width [Integer] how wide the rectangle should be.
65
+ # @param height [Integer] how tall the rectangle should be.
66
+ # @param colour [Symbol] The stroke colour used for the rectangle
67
+ # (either black, white, or red).
68
+ # @param bgcolour [Symbol] The fill colour used for the rectangle
69
+ # (either black, white, or red).
70
+ # @param pen_width [Integer] The width in pixels of the stroke.
71
+ def initialize(x: nil, y: nil, width: nil, height: nil, colour: :black, bgcolour: :white, pen_width: 1, fillpattern: :none, strokepattern: :solid)
72
+ Widget::check_patterns [fillpattern, strokepattern]
73
+ raise(AlignmentException, "Rect: x and width must both be a multiple of 8") if x % 8 != 0 or width % 8 != 0
74
+ @pen_width = pen_width
75
+ @fillpattern = fillpattern
76
+ @strokepattern = strokepattern
77
+ super(x: x, y: y, width: width, height: height, colour: colour, bgcolour: bgcolour)
78
+ end
79
+
80
+ ##
81
+ # Convert the widget into an array for sending to the SyncSign service.
82
+ def to_a
83
+ {
84
+ 'type': 'RECTANGLE',
85
+ 'data': {
86
+ 'block': {x: @x, y: @y, w: @width, h: @height},
87
+ 'fillColor': @bgcolour.to_s.upcase,
88
+ 'fillPattern': @fillpattern.to_s.upcase,
89
+ 'strokeColor': @colour.to_s.upcase,
90
+ 'strokePattern': @strokepattern.to_s.upcase,
91
+ 'strokeThickness': @pen_width
92
+ }
93
+ }
94
+ end
95
+ end
96
+
97
+ ##
98
+ # A widget that draws a line.
99
+ class Line
100
+ attr_accessor :x0, :y0, :x1, :y1, :bgcolour, :colour, :pattern
101
+
102
+ ##
103
+ # Initialize a new line widget.
104
+ # @param x0 [Integer] horizontal position of the starting point of the line.
105
+ # @param y0 [Integer] vertical position of the starting point of the line.
106
+ # @param x1 [Integer] horizontal position of the ending point of the line.
107
+ # @param y1 [Integer] vertical position of the ending point of the line.
108
+ # @param colour [Symbol] The stroke colour used for the rectangle
109
+ # (either black, white, or red).
110
+ # @param bgcolour [Symbol] The fill colour used for the rectangle
111
+ # (either black, white, or red).
112
+ # @param pattern [Symbol] The linestyle to use when drawing the line, one of solid, interleave, dash_tiny, dash_mid, or dash_wide.
113
+ def initialize(x0: nil, y0: nil, x1: nil, y1: nil, bgcolour: :white, colour: :black, pattern: :solid)
114
+ Widget::check_colours [colour, bgcolour]
115
+ Widget::check_patterns [pattern]
116
+ @x0 = x0
117
+ @y0 = y0
118
+ @x1 = x1
119
+ @y1 = y1
120
+ @colour = colour
121
+ @bgcolour = bgcolour
122
+ @pattern = pattern
123
+ end
124
+
125
+ ##
126
+ # Convert the widget into an array for sending to the SyncSign service.
127
+ def to_a
128
+ {
129
+ 'type': 'LINE',
130
+ 'data': {
131
+ 'block': {x0: @x0, y0: @y0, x1: @x1, y1: @y1},
132
+ 'backgroundColor': @bgcolour.to_s.upcase,
133
+ 'lineColor': @colour.to_s.upcase,
134
+ 'linePattern': @pattern.to_s.upcase
135
+ }
136
+ }
137
+ end
138
+ end
139
+
140
+ ##
141
+ # A widget that draws a circle.
142
+ class Circle < Item
143
+ attr_accessor :radius, :bgcolour, :colour, :fillpattern, :strokepattern
144
+
145
+ ##
146
+ # Initialize a new circle widget.
147
+ # @param x [Integer] horizontal position of the centre of the circle.
148
+ # @param y [Integer] vertical position of the centre of the circle
149
+ # @param radius [Integer] The radius of the circle in pixels.
150
+ # @param colour [Symbol] The stroke colour used for the circle
151
+ # (either black, white, or red).
152
+ # @param bgcolour [Symbol] The fill colour used for the circle
153
+ # (either black, white, or red).
154
+ # @param fillpattern [Symbol] The fill pattern to use when filling the circle.
155
+ # @param strokepattern [Symbol] The stroke pattern to use when drawing the circle.
156
+ # @param pen_width [Integer] The thickness in pixels of the stroke.
157
+ def initialize(x: nil, y: nil, radius: nil, bgcolour: :white, colour: :black, fillpattern: :none, strokepattern: :solid, pen_width: 1)
158
+ Widget::check_colours [colour, bgcolour]
159
+ Widget::check_patterns [fillpattern, strokepattern]
160
+ @radius = radius
161
+ @colour = colour
162
+ @bgcolour = bgcolour
163
+ @fillpattern = fillpattern
164
+ @strokepattern = strokepattern
165
+ @pen_width = pen_width
166
+ super(x: x, y:y)
167
+ end
168
+
169
+ ##
170
+ # Convert the widget into an array for sending to the SyncSign service.
171
+ def to_a
172
+ {
173
+ 'type': 'CIRCLE',
174
+ 'data': {
175
+ 'center': {x: @x, y: @y},
176
+ 'fillColor': @bgcolour.to_s.upcase,
177
+ 'fillPattern': @fillpattern.to_s.upcase,
178
+ 'strokeColor': @colour.to_s.upcase,
179
+ 'strokePattern': @strokepattern.to_s.upcase,
180
+ 'strokeThickness': @pen_width
181
+ }
182
+ }
183
+ end
184
+ end
185
+
186
+ ##
187
+ # A widget that draws a text box.
188
+ class Textbox < Box
189
+ attr_accessor :font, :size, :id, :align, :text
190
+
191
+ ##
192
+ # Initialize a new text box widget.
193
+ # @param x [Integer] horizontal position of the left side of the text box.
194
+ # @param y [Integer] vertical position of the top of the text box.
195
+ # @param width [Integer] how wide the text box should be.
196
+ # @param height [Integer] how tall the text box should be.
197
+ # @param colour [Symbol] The text colour used for the text.
198
+ # @param bgcolour [Symbol] The background colour used for the text box.
199
+ # @param font [Symbol] The font to use when drawing the text.
200
+ # @param size [Integer] The point size to use when drawing the text.
201
+ # @param align [Symbol] Whether to align the text left, center, or right.
202
+ # @param text [String] The text to draw in the box.
203
+ # @param id [String] An ID value to attach to the text box.
204
+ def initialize(x: nil, y: nil, width: nil, height: nil, colour: :black, bgcolour: :white, font: nil, size: nil, id: nil, align: :left, text: nil)
205
+ check_font(font: font, size: size)
206
+ raise(AlignmentException, "Textbox: either y or height must be a multiple of 8") if y % 8 != 0 and height % 8 != 0
207
+ raise(AlignmentException, "Textbox: width must be a multiple of 8") if width % 8 != 0
208
+ @font = font.upcase
209
+ @size = size
210
+ @id = id
211
+ @align = align
212
+ @text = text
213
+ super(x: x, y: y, width: width, height: height, colour: colour, bgcolour: bgcolour)
214
+ end
215
+
216
+ ##
217
+ # Convert the widget into an array for sending to the SyncSign service.
218
+ def to_a
219
+ {
220
+ 'type': 'TEXT',
221
+ 'data': {
222
+ 'block': {x: @x, y: @y, w: @width, h: @height},
223
+ 'textColor': @colour.to_s.upcase,
224
+ 'textAlign': @align.to_s.upcase,
225
+ 'font': "#{@font}_#{@size.to_s}",
226
+ 'text': @text
227
+ }
228
+ }
229
+ end
230
+
231
+ def check_font(font: nil, size: nil)
232
+ available_sizes = {
233
+ :ddin => [16, 24, 32, 48, 64, 128],
234
+ :ddin_condensed => [16, 24, 32, 48, 64],
235
+ :charriot => [10],
236
+ :aprilsans => [10, 16, 24],
237
+ :roboto_condensed => [24, 48],
238
+ :roboto_slab => [24, 48],
239
+ :yanone_kaffeesatz => [24, 44],
240
+ :kaushan_script => [20, 32],
241
+ :sriracha => [24],
242
+ :dorsa => [32],
243
+ :londrina_outline => [36],
244
+ :bungee_shade => [36],
245
+ :noto_serif => [16],
246
+ :noto_sans => [24, 40]
247
+ }
248
+
249
+ if(!available_sizes.keys.include? font) then
250
+ raise ArgumentError, "#{font} is not a valid font. Available fonts: #{available_sizes.keys}"
251
+ end
252
+ if(!available_sizes[font].include? size) then
253
+ raise ArgumentError, "#{font} is not available in size #{size}. Available sizes for this font: #{available_sizes[font].join(", ")}"
254
+ end
255
+ end
256
+ end
257
+
258
+ ##
259
+ # A widget that draws a QR code.
260
+ class QRCode < Item
261
+ # @return [Integer] scale of the QR code (how many pixels to use to
262
+ # represent each base pixel).
263
+ attr_accessor :scale
264
+ # @return [Integer] the version (which is actually size, in QR-speak)
265
+ # of this QR code.
266
+ attr_accessor :version
267
+ # @return [Symbol] the level of error checking code for this QR code,
268
+ # either :low, :medium, :quartile, or :high.
269
+ attr_accessor :ecclevel
270
+ # @return [String] the text to encode in this QR code.
271
+ attr_accessor :text
272
+
273
+ ##
274
+ # Initialize a new QR code widget.
275
+ # @param x [Integer] horizontal position of the left side of the QR code.
276
+ # @param y [Integer] vertical position of the top of the QR code.
277
+ # @param scale [Integer] scale of the QR code (how many pixels to use to
278
+ # represent each base pixel).
279
+ # @param version [Integer] the version (which is actually size, in QR-speak)
280
+ # of this QR code.
281
+ # @param ecclevel [Symbol] the level of error checking code for this QR code,
282
+ # either :low, :medium, :quartile, or :high.
283
+ # @param text [String] the text to encode in this QR code.
284
+ def initialize(x: nil, y: nil, scale: 4, version: 2, ecclevel: :medium, text: nil)
285
+ @scale = scale
286
+ @version = version
287
+ @ecclevel = ecclevel
288
+ @text = text
289
+
290
+ super(x: x, y: y)
291
+ end
292
+
293
+ ##
294
+ # Convert the widget into an array for sending to the SyncSign service.
295
+ def to_a
296
+ {
297
+ 'type': 'QRCODE',
298
+ 'data': {
299
+ 'scale': @scale,
300
+ 'eccLevel': @ecclevel.to_s.upcase,
301
+ 'version': @version,
302
+ 'position': {x: @x, y: @y},
303
+ 'text': @text
304
+ }
305
+ }
306
+ end
307
+ end
308
+
309
+ def self.check_colours(colours)
310
+ colours.each do |colour|
311
+ next if [:white, :black, :red].include? colour
312
+ raise ArgumentError, "Colour must be :white, :black, or :red."
313
+ end
314
+ end
315
+
316
+ def self.check_patterns(patterns)
317
+ patterns.each do |pattern|
318
+ next if [:solid, :interleave, :dash_tiny, :dash_medium, :dash_wide, :none].include? pattern
319
+ raise ArgumentError, "Pattern must be :solid, :interleave, :dash_tiny, :dash_medium, :dash_wide, or :none."
320
+ end
321
+ end
322
+ end
323
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: syncsign
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - sarahemm
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-16 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Interface library for SyncSign e-paper displays
14
+ email: github@sen.cx
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - Rakefile
21
+ - lib/syncsign.rb
22
+ - lib/syncsign/hub.rb
23
+ - lib/syncsign/node-display.rb
24
+ - lib/syncsign/node.rb
25
+ - lib/syncsign/service.rb
26
+ - lib/syncsign/template.rb
27
+ - lib/syncsign/version.rb
28
+ - lib/syncsign/widgets.rb
29
+ homepage: http://github.com/sarahemm/ruby-syncsign
30
+ licenses:
31
+ - MIT
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.7.9
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: SyncSign interface library
53
+ test_files: []