Added GPIO web panel

This commit is contained in:
Fabio Manganiello 2019-12-22 18:09:19 +01:00
parent d33494419a
commit a23f5446da
5 changed files with 130 additions and 11 deletions

View file

@ -0,0 +1,39 @@
@import 'common/vars';
.gpio-container {
display: flex;
flex-direction: column;
height: 100%;
overflow: auto;
.refresh {
border-bottom: $default-border-2;
background: $default-bg-5;
button {
border: 0;
&:hover {
color: $default-hover-fg;
}
}
}
.pins {
.pin {
padding: 1em;
border-bottom: $default-border-2;
display: flex;
flex-direction: row;
align-items: center;
&:nth-child(even) {
background: $modal-header-bg;
}
&:hover {
background: $hover-bg;
}
}
}
}

View file

@ -0,0 +1,35 @@
Vue.component('gpio', {
template: '#tmpl-gpio',
props: ['config'],
data: function() {
return {
pins: {},
};
},
methods: {
refresh: async function() {
const pins = await request('gpio.read_all');
this.pins = pins.reduce((pins, pin) => {
pins[pin.pin] = {
name: pin.name,
number: pin.pin,
on: !!pin.value,
};
return pins;
}, {});
},
toggle: async function(pin) {
await request('gpio.write', {pin: pin, value: +(!this.pins[pin].on)});
this.refresh();
},
},
mounted: function() {
this.refresh();
},
});

View file

@ -5,6 +5,8 @@
'camera.pi': 'fab fa-raspberry-pi', 'camera.pi': 'fab fa-raspberry-pi',
'camera.ir.mlx90640': 'fas fa-sun', 'camera.ir.mlx90640': 'fas fa-sun',
'execute': 'fas fa-play', 'execute': 'fas fa-play',
'gpio': 'fas fa-plug',
'gpio.zeroborg': 'fas fa-robot',
'light.hue': 'fa fa-lightbulb', 'light.hue': 'fa fa-lightbulb',
'media.mplayer': 'fa fa-film', 'media.mplayer': 'fa fa-film',
'media.mpv': 'fa fa-film', 'media.mpv': 'fa fa-film',

View file

@ -0,0 +1,21 @@
<script type="text/x-template" id="tmpl-gpio">
<div class="gpio-container">
<div class="refresh pull-right">
<button class="btn btn-default btn-refresh" title="Refresh">
<i class="fa fa-retweet">
</button>
</div>
<div class="pins">
<div class="pin"
v-for="(pin, number) in pins"
:key="number">
<div class="col-10 name" v-text="pin.name || number"></div>
<div class="col-2 toggle pull-right">
<toggle-switch :value="pin.on" @toggled="toggle(number)"></toggle-switch>
</div>
</div>
</div>
</div>
</script>

View file

@ -2,6 +2,7 @@
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com> .. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
""" """
import threading
from typing import Any, Optional, Dict, Union from typing import Any, Optional, Dict, Union
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
@ -34,10 +35,23 @@ class GpioPlugin(Plugin):
super().__init__(**kwargs) super().__init__(**kwargs)
self.mode = self._get_mode(mode) self.mode = self._get_mode(mode)
self._initialized = False
self._init_lock = threading.RLock()
self._initialized_pins = {}
self.pins_by_name = pins if pins else {} self.pins_by_name = pins if pins else {}
self.pins_by_number = {number: name self.pins_by_number = {number: name
for (name, number) in self.pins_by_name.items()} for (name, number) in self.pins_by_name.items()}
def _init_board(self):
import RPi.GPIO as gpio
with self._init_lock:
if self._initialized:
return
gpio.setmode(self.mode)
self._initialized = True
def _get_pin_number(self, pin): def _get_pin_number(self, pin):
try: try:
pin = int(str(pin)) pin = int(str(pin))
@ -58,15 +72,13 @@ class GpioPlugin(Plugin):
@action @action
def write(self, pin: Union[int, str], value: Union[int, bool], def write(self, pin: Union[int, str], value: Union[int, bool],
name: Optional[str] = None, mode: Optional[str] = None) -> Dict[str, Any]: name: Optional[str] = None) -> Dict[str, Any]:
""" """
Write a byte value to a pin. Write a byte value to a pin.
:param pin: PIN number or configured name :param pin: PIN number or configured name
:param name: Optional name for the written value (e.g. "temperature" or "humidity") :param name: Optional name for the written value (e.g. "temperature" or "humidity")
:param value: Value to write :param value: Value to write
:param mode: If a PIN number is specified then you can override the default 'mode'
default parameter
Response:: Response::
@ -80,10 +92,14 @@ class GpioPlugin(Plugin):
import RPi.GPIO as gpio import RPi.GPIO as gpio
self._init_board()
name = name or pin name = name or pin
pin = self._get_pin_number(pin) pin = self._get_pin_number(pin)
mode = self._get_mode(mode) if mode else self.mode
gpio.setmode(mode) if pin not in self._initialized_pins or self._initialized_pins[pin] != gpio.OUT:
gpio.setup(pin, gpio.OUT)
self._initialized_pins[pin] = gpio.OUT
gpio.setup(pin, gpio.OUT) gpio.setup(pin, gpio.OUT)
gpio.output(pin, value) gpio.output(pin, value)
@ -95,15 +111,12 @@ class GpioPlugin(Plugin):
} }
@action @action
def read(self, pin: Union[int, str], name: Optional[str] = None, def read(self, pin: Union[int, str], name: Optional[str] = None) -> Dict[str, Any]:
mode: Optional[str] = None) -> Dict[str, Any]:
""" """
Reads a value from a PIN. Reads a value from a PIN.
:param pin: PIN number or configured name. :param pin: PIN number or configured name.
:param name: Optional name for the read value (e.g. "temperature" or "humidity") :param name: Optional name for the read value (e.g. "temperature" or "humidity")
:param mode: If a PIN number is specified then you can override the default 'mode'
default parameter
Response:: Response::
@ -117,10 +130,14 @@ class GpioPlugin(Plugin):
import RPi.GPIO as gpio import RPi.GPIO as gpio
self._init_board()
name = name or pin name = name or pin
pin = self._get_pin_number(pin) pin = self._get_pin_number(pin)
gpio.setmode(gpio.BCM)
if pin not in self._initialized_pins:
gpio.setup(pin, gpio.IN) gpio.setup(pin, gpio.IN)
self._initialized_pins[pin] = gpio.IN
val = gpio.input(pin) val = gpio.input(pin)
return { return {
@ -154,8 +171,13 @@ class GpioPlugin(Plugin):
@action @action
def cleanup(self): def cleanup(self):
"""
Cleanup the state of the GPIO and resets PIN values.
"""
import RPi.GPIO as gpio import RPi.GPIO as gpio
gpio.cleanup() gpio.cleanup()
self._initialized_pins = {}
self._initialized = False
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et: