pigpiod 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 +7 -0
- data/exe/pigpio_mqtt_bridge +63 -0
- data/lib/pi_gpio/errors.rb +162 -0
- data/lib/pi_gpio/gpio.rb +82 -0
- data/lib/pigpiod.rb +38 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7402311d7d55303c25209cbe6dd119955681714fe86e8ee830a0931575ddc79e
|
4
|
+
data.tar.gz: 9a1805587185f5724683d4f36801bb534ea8b5cd256e08f288161c6a59dace40
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 608f85c221dc559a57c9273febf63c9c583049caa28a7e1fd506c9bb9c48bc0320cff7ce8694e8b58ec8cf8a2f019fc29671b6545cb766f3c446b0faee1b234f
|
7
|
+
data.tar.gz: 01e51a27bd50621c79380383735fb5a954379c552d94d1a636242be1830ef16ccc956888ca2ee4e454b3e61e03693a12a6e9785ef93bf2cefff29efbf556d397
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "mqtt-homeassistant"
|
5
|
+
require "optparse"
|
6
|
+
require "pigpiod"
|
7
|
+
require "yaml"
|
8
|
+
|
9
|
+
config_file = nil
|
10
|
+
device_id = "pigpio"
|
11
|
+
|
12
|
+
options = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: pigpio_mqtt_bridge MQTT_URI [options]"
|
14
|
+
|
15
|
+
opts.on("-c", "--config=YML", "Specify a configuration YAML file to set up the pins") { |v| config_file = v }
|
16
|
+
opts.on("-d", "--device-id=ID", "Specify Homie device ID") { |v| device_id = v }
|
17
|
+
opts.on("-h", "--help", "Prints this help") do
|
18
|
+
puts opts
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
options.parse!
|
24
|
+
|
25
|
+
unless ARGV.length == 1
|
26
|
+
puts options
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
config = {}
|
31
|
+
config = YAML.load_file(config_file) if config_file
|
32
|
+
|
33
|
+
config.each do |pin, gpio_config|
|
34
|
+
pin = pin.to_i
|
35
|
+
raise "Unrecognized gpio" unless (gpio = PiGPIO.instance.gpios[pin])
|
36
|
+
|
37
|
+
gpio.mode = gpio_config[:mode].to_sym if gpio_config[:mode]
|
38
|
+
gpio.pull_up_down = gpio_config[:pull_up_down].to_sym if gpio_config[:pull_up_down]
|
39
|
+
gpio.invert_logic = gpio_config[:invert_logic] if gpio_config[:invert_logic]
|
40
|
+
end
|
41
|
+
|
42
|
+
homie = MQTT::Homie::Device.new(device_id, "PiGPIO", mqtt: ARGV[0])
|
43
|
+
homie.home_assistant_device = {
|
44
|
+
manufacturer: "Raspberry Pi Foundation"
|
45
|
+
}
|
46
|
+
|
47
|
+
PiGPIO.instance.gpios.each do |gpio|
|
48
|
+
homie.node("gpio#{gpio.g}", "GPIO #{gpio.g}", "GPIO") do |node|
|
49
|
+
node.property("mode", "Mode", :enum, gpio.mode, format: PiGPIO::GPIO::MODES)
|
50
|
+
node.property("level", "Logic Level", :boolean, gpio.level, hass: :switch) do |value, prop|
|
51
|
+
next unless gpio.mode == :output
|
52
|
+
|
53
|
+
prop.value = gpio.level = value
|
54
|
+
end
|
55
|
+
node.property("pull-up-down", "Internal Pull Up/Down Resistor", :enum, retained: false,
|
56
|
+
format: %w[up down off]) do |value|
|
57
|
+
gpio.pull_up_down = value.to_sym
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
homie.publish
|
63
|
+
homie.join
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PiGPIO
|
4
|
+
class Error < RuntimeError
|
5
|
+
attr_reader :code
|
6
|
+
|
7
|
+
def initialize(code, message)
|
8
|
+
@code = code
|
9
|
+
super(message)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
ERRORS = [
|
14
|
+
"gpioInitialise failed",
|
15
|
+
"GPIO not 0-31",
|
16
|
+
"GPIO not 0-53",
|
17
|
+
"mode not 0-7",
|
18
|
+
"level not 0-1",
|
19
|
+
"pud not 0-2",
|
20
|
+
"pulsewidth not 0 or 500-2500",
|
21
|
+
"dutycycle outside set range",
|
22
|
+
"timer not 0-9",
|
23
|
+
"ms not 10-60000",
|
24
|
+
"timetype not 0-1",
|
25
|
+
"seconds < 0",
|
26
|
+
"micros not 0-999999",
|
27
|
+
"gpioSetTimerFunc failed",
|
28
|
+
"timeout not 0-60000",
|
29
|
+
"DEPRECATED: no alert func",
|
30
|
+
"clock peripheral not 0-1",
|
31
|
+
"DEPRECATED: bad clk source",
|
32
|
+
"clock micros not 1, 2, 4, 5, 8, or 10",
|
33
|
+
"buf millis not 100-10000",
|
34
|
+
"dutycycle range not 25-40000",
|
35
|
+
"signum not 0-63",
|
36
|
+
"can't open pathname",
|
37
|
+
"no handle available",
|
38
|
+
"unknown handle",
|
39
|
+
"ifFlags > 4",
|
40
|
+
"DMA channel not 0-15",
|
41
|
+
"socket port not 1024-32000",
|
42
|
+
"unrecognized fifo command",
|
43
|
+
"DMA secondary channel not 0-15",
|
44
|
+
"function called before gpioInitialise",
|
45
|
+
"function called after gpioInitialise",
|
46
|
+
"waveform mode not 0-3",
|
47
|
+
"bad parameter in gpioCfgInternals call",
|
48
|
+
"baud rate not 50-250K(RX)/50-1M(TX)",
|
49
|
+
"waveform has too many pulses",
|
50
|
+
"waveform has too many chars",
|
51
|
+
"no bit bang serial read on GPIO",
|
52
|
+
"bad (null) serial structure parameter",
|
53
|
+
"bad (null) serial buf parameter",
|
54
|
+
"GPIO operation not permitted",
|
55
|
+
"one or more GPIO not permitted",
|
56
|
+
"bad WVSC subcommand",
|
57
|
+
"bad WVSM subcommand",
|
58
|
+
"bad WVSP subcommand",
|
59
|
+
"trigger pulse length not 1-100",
|
60
|
+
"invalid script",
|
61
|
+
"unknown script id",
|
62
|
+
"add serial data offset > 30 minutes",
|
63
|
+
"GPIO already in use",
|
64
|
+
"must read at least a byte at a time",
|
65
|
+
"script parameter id not 0-9",
|
66
|
+
"script has duplicate tag",
|
67
|
+
"script has too many tags",
|
68
|
+
"illegal script command",
|
69
|
+
"script variable id not 0-149",
|
70
|
+
"no more room for scripts",
|
71
|
+
"can't allocate temporary memory",
|
72
|
+
"socket read failed",
|
73
|
+
"socket write failed",
|
74
|
+
"too many script parameters (> 10)",
|
75
|
+
"script initialising",
|
76
|
+
"script has unresolved tag",
|
77
|
+
"bad MICS delay (too large)",
|
78
|
+
"bad MILS delay (too large)",
|
79
|
+
"non existent wave id",
|
80
|
+
"No more CBs for waveform",
|
81
|
+
"No more OOL for waveform",
|
82
|
+
"attempt to create an empty waveform",
|
83
|
+
"no more waveforms",
|
84
|
+
"can't open I2C device",
|
85
|
+
"can't open serial device",
|
86
|
+
"can't open SPI device",
|
87
|
+
"bad I2C bus",
|
88
|
+
"bad I2C address",
|
89
|
+
"bad SPI channel",
|
90
|
+
"bad i2c/spi/ser open flags",
|
91
|
+
"bad SPI speed",
|
92
|
+
"bad serial device name",
|
93
|
+
"bad serial baud rate",
|
94
|
+
"bad i2c/spi/ser parameter",
|
95
|
+
"i2c write failed",
|
96
|
+
"i2c read failed",
|
97
|
+
"bad SPI count",
|
98
|
+
"ser write failed",
|
99
|
+
"ser read failed",
|
100
|
+
"ser read no data available",
|
101
|
+
"unknown command",
|
102
|
+
"spi xfer/read/write failed",
|
103
|
+
"bad (NULL) pointer",
|
104
|
+
"no auxiliary SPI on Pi A or B",
|
105
|
+
"GPIO is not in use for PWM",
|
106
|
+
"GPIO is not in use for servo pulses",
|
107
|
+
"GPIO has no hardware clock",
|
108
|
+
"GPIO has no hardware PWM",
|
109
|
+
"invalid hardware PWM frequency",
|
110
|
+
"hardware PWM dutycycle not 0-1M",
|
111
|
+
"invalid hardware clock frequency",
|
112
|
+
"need password to use hardware clock 1",
|
113
|
+
"illegal, PWM in use for main clock",
|
114
|
+
"serial data bits not 1-32",
|
115
|
+
"serial (half) stop bits not 2-8",
|
116
|
+
"socket/pipe message too big",
|
117
|
+
"bad memory allocation mode",
|
118
|
+
"too many I2C transaction segments",
|
119
|
+
"an I2C transaction segment failed",
|
120
|
+
"SMBus command not supported by driver",
|
121
|
+
"no bit bang I2C in progress on GPIO",
|
122
|
+
"bad I2C write length",
|
123
|
+
"bad I2C read length",
|
124
|
+
"bad I2C command",
|
125
|
+
"bad I2C baud rate, not 50-500k",
|
126
|
+
"bad chain loop count",
|
127
|
+
"empty chain loop",
|
128
|
+
"too many chain counters",
|
129
|
+
"bad chain command",
|
130
|
+
"bad chain delay micros",
|
131
|
+
"chain counters nested too deeply",
|
132
|
+
"chain is too long",
|
133
|
+
"deprecated function removed",
|
134
|
+
"bit bang serial invert not 0 or 1",
|
135
|
+
"bad ISR edge value, not 0-2",
|
136
|
+
"bad ISR initialisation",
|
137
|
+
"loop forever must be last command",
|
138
|
+
"bad filter parameter",
|
139
|
+
"bad pad number",
|
140
|
+
"bad pad drive strength",
|
141
|
+
"file open failed",
|
142
|
+
"bad file mode",
|
143
|
+
"bad file flag",
|
144
|
+
"bad file read",
|
145
|
+
"bad file write",
|
146
|
+
"file not open for read",
|
147
|
+
"file not open for write",
|
148
|
+
"bad file seek",
|
149
|
+
"no files match pattern",
|
150
|
+
"no permission to access file",
|
151
|
+
"file is a directory",
|
152
|
+
"bad shell return status",
|
153
|
+
"bad script name",
|
154
|
+
"bad SPI baud rate, not 50-500k",
|
155
|
+
"no bit bang SPI in progress on GPIO",
|
156
|
+
"bad event id",
|
157
|
+
"Used by Python",
|
158
|
+
"not available on BCM2711",
|
159
|
+
"only available on BCM2711"
|
160
|
+
].freeze
|
161
|
+
private_constant :ERRORS
|
162
|
+
end
|
data/lib/pi_gpio/gpio.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PiGPIO
|
4
|
+
class GPIO
|
5
|
+
MODE_VALUES = %i[
|
6
|
+
input
|
7
|
+
output
|
8
|
+
alt5
|
9
|
+
alt4
|
10
|
+
alt0
|
11
|
+
alt1
|
12
|
+
alt2
|
13
|
+
alt3
|
14
|
+
].freeze
|
15
|
+
MODE_CODES = {
|
16
|
+
input: "R",
|
17
|
+
output: "W",
|
18
|
+
alt0: 0,
|
19
|
+
alt1: 1,
|
20
|
+
alt2: 2,
|
21
|
+
alt3: 3,
|
22
|
+
alt4: 4,
|
23
|
+
alt5: 5
|
24
|
+
}.freeze
|
25
|
+
MODES = MODE_CODES.keys.freeze
|
26
|
+
private_constant :MODE_VALUES, :MODE_CODES
|
27
|
+
|
28
|
+
attr_accessor :invert_logic
|
29
|
+
attr_reader :g
|
30
|
+
|
31
|
+
def initialize(pigpio, g) # rubocop:disable Naming/MethodParameterName
|
32
|
+
@pigpio = pigpio
|
33
|
+
@g = g
|
34
|
+
@invert_logic = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
vals = {
|
39
|
+
g: g,
|
40
|
+
invert_logic: invert_logic,
|
41
|
+
mode: @mode
|
42
|
+
}.compact
|
43
|
+
"#<PiGPIO::GPIO #{vals.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")}>"
|
44
|
+
end
|
45
|
+
|
46
|
+
def mode
|
47
|
+
@mode ||= MODE_VALUES[command("mg #{g}")]
|
48
|
+
end
|
49
|
+
|
50
|
+
def mode=(value)
|
51
|
+
raise ArgumentError, "Invalid mode #{value.inspect}" unless MODE_CODES.key?(value)
|
52
|
+
|
53
|
+
@mode = nil
|
54
|
+
command("m #{g} #{MODE_CODES[value]}")
|
55
|
+
end
|
56
|
+
|
57
|
+
def pull_up_down=(value)
|
58
|
+
raise ArgumentError, "Invalid setting #{value.inspect}" unless %i[up down off].include?(value)
|
59
|
+
|
60
|
+
command("pud #{g} #{value.to_s.first}")
|
61
|
+
end
|
62
|
+
|
63
|
+
def level
|
64
|
+
result = !command("r #{g}").zero?
|
65
|
+
result = !result if invert_logic
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def level=(value)
|
70
|
+
raise ArgumentError, "Invalid level #{value.inspect}" unless [true, false].include?(value)
|
71
|
+
|
72
|
+
value = !value if invert_logic
|
73
|
+
command("w #{g} #{value ? 1 : 0}")
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def command(command)
|
79
|
+
@pigpio.send(:command, command)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/pigpiod.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "io/wait"
|
4
|
+
require "singleton"
|
5
|
+
|
6
|
+
require "pi_gpio/errors"
|
7
|
+
require "pi_gpio/gpio"
|
8
|
+
|
9
|
+
class PiGPIO
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
attr_reader :gpios
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@pigpio = File.open("/dev/pigpio", "wb")
|
16
|
+
@pigout = File.open("/dev/pigout", "rb")
|
17
|
+
|
18
|
+
@gpios = Array.new(54) { |g| GPIO.new(self, g) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspect
|
22
|
+
"#<PiGPIO>"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def command(command)
|
28
|
+
@pigpio.puts(command)
|
29
|
+
@pigpio.flush
|
30
|
+
@pigout.wait_readable
|
31
|
+
result = @pigout.read_nonblock(256).strip.to_i
|
32
|
+
if result.negative?
|
33
|
+
error_index = -result - 1
|
34
|
+
raise Error.new(result, ERRORS[error_index])
|
35
|
+
end
|
36
|
+
result
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pigpiod
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cody Cutrer
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mqtt-homeassistant
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '9.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '9.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.23'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.23'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-performance
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.12'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.12'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.6'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.6'
|
97
|
+
description:
|
98
|
+
email: cody@cutrer.com'
|
99
|
+
executables:
|
100
|
+
- pigpio_mqtt_bridge
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- exe/pigpio_mqtt_bridge
|
105
|
+
- lib/pi_gpio/errors.rb
|
106
|
+
- lib/pi_gpio/gpio.rb
|
107
|
+
- lib/pigpiod.rb
|
108
|
+
homepage: https://github.com/ccutrer/ruby-pigpiod
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata:
|
112
|
+
rubygems_mfa_required: 'true'
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '2.5'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubygems_version: 3.2.5
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Publish pigpiod access to MQTT
|
132
|
+
test_files: []
|