syncsign 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 +7 -0
- data/README.md +38 -0
- data/Rakefile +38 -0
- data/lib/syncsign.rb +9 -0
- data/lib/syncsign/hub.rb +25 -0
- data/lib/syncsign/node-display.rb +18 -0
- data/lib/syncsign/node.rb +73 -0
- data/lib/syncsign/service.rb +89 -0
- data/lib/syncsign/template.rb +50 -0
- data/lib/syncsign/version.rb +4 -0
- data/lib/syncsign/widgets.rb +323 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -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
|
data/README.md
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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]
|
data/lib/syncsign.rb
ADDED
data/lib/syncsign/hub.rb
ADDED
@@ -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,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: []
|