New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Idea: create gpiozero yaml interface #548
Comments
|
I think the answer to "Find a use for it?" will be the key to seeing how useful such a feature would be, and what sort of direction it should be pushed in :) Since the YAML devices:
- led: LED, 17
- btn: Button, 18
connections:
- led: btnisn't really that much more succinct than the equivalent GpioZero code from gpiozero import *
led = LED(17)
btn = Button(18)
led.source = btn.valuesAnd obviously yaml->python conversion will be much easier than python->yaml conversion ;-) |
|
Put into a class and automated classes dict: import yaml
import gpiozero
from signal import pause
classes = {
name: cls
for name, cls in gpiozero.__dict__.items()
if isinstance(cls, type) and issubclass(cls, gpiozero.Device)
}
class GPIOZeroYamlParser():
def __init__(self, config_file):
with open(config_file, 'r') as f:
self.config = yaml.load(f)
self.devices = {}
for device in self.config['devices']:
for obj_name, data in device.items():
class_name, *args = data.split(', ')
ClassName = classes[class_name]
self.devices[obj_name] = ClassName(*[int(arg) for arg in args])
for connection in self.config['connections']:
for source_device_ref, value_device_ref in connection.items():
source_device = self.devices[source_device_ref]
value_device = self.devices[value_device_ref]
source_device.source = value_device.values
if __name__ == '__main__':
parser = GPIOZeroYamlParser('led_button.yml')
pause() |
|
Export to Python file: class GPIOZeroYamlParser():
def __init__(self, config_file):
with open(config_file, 'r') as f:
self.config = yaml.load(f)
self.devices = {}
self.device_data = {}
self.classes = set()
for device in self.config['devices']:
for obj_name, data in device.items():
class_name, *args = data.split(', ')
ClassName = classes[class_name]
self.classes.add(ClassName)
self.devices[obj_name] = ClassName(*[int(arg) for arg in args])
self.device_data[obj_name] = {
'class_name': class_name,
'args': [int(arg) for arg in args]
}
for connection in self.config['connections']:
for source_device_ref, value_device_ref in connection.items():
source_device = self.devices[source_device_ref]
value_device = self.devices[value_device_ref]
source_device.source = value_device.values
def to_python(self):
classes = ', '.join(obj.__name__ for obj in self.classes)
devices = '\n'.join(
'{} = {}({})'.format(obj_name, data['class_name'], *data['args'])
for obj_name, data in self.device_data.items()
)
connections = '\n'.join(
'{}.source = {}.values'.format(source_device, value_device)
for connection in self.config['connections']
for source_device, value_device in connection.items()
)
return """from gpiozero import {}
from signal import pause
{}
{}
pause()""".format(classes, devices, connections) |
|
Probably makes sense to have separate |
|
True |
|
Just found this project (not particularly new) doing something similar with RPi.GPIO: https://github.com/projectweekend/Pi-Pin-Manager - but it's more trying to solve the boilerplate problem than create an interchange format. Nevertheless, interesting. |
Hmmm, I wonder if you could serialise a "current gpiozero session" (e.g. as created in the REPL) out to a YAML file, by iterating over all the in-use pins and outputting their "gpiozero state"; which would allow you to 'persist / recreate' a REPL session, without having to re-type or copy'n'paste all your current code? ;-) |
|
Added JSON equivalent: https://gist.github.com/bennuttall/d34bcf7d01a186a7833d3f6e8a315c3d If you only want Python output without touching the pins, just use mockpin pin factory. I haven't added support for composite devices or source tools yet. |
|
Just occurred to me that storing strings like |
|
True. It's a balance between not being too verbose in the markup. It should probably be a list of arguments, or even a dict (eugh), really, but I'm just being minimal. |
I had an idea and I've thrown together a proof-of-concept demo.
Imagine a YAML file which described a series of gpiozero objects to be used, and how they were connected. For example:
And imagine you could "import" that file somehow and it set up gpiozero objects for each device, and "connected" the devices using source/values. So this YAML file was just a shorthand way of describing the object behaviour.
I threw together this file which does just that:
It's a bit of a hack right now, but I just wanted to see if it would work. Here's it working in a shell:
Why?
I thought about a simple way to create or store a set of gpiozero "rules". Perhaps it could be used by a GUI to create Python code from blocks or something.
I think it could work with:
I think it's limited to just these things, no other objects, no other code, no main loop - just set up events and source/values and pause. I think composite devices should work, but setting their source will be tricky if not trivially coded.
Note the YAML file could be more verbose, describing all the parameters properly, rather than splitting on a comma, but I considered this style to align with the simple nature of gpiozero, and of un-named, positional arguments. I think you could add keyword arguments easily enough too.
Todo:
Plus lots of cleanup like turn it into a class, automate the string: class dict, etc.
I might be mad to think this is useful. But I know better than not to share my mad ideas.
The text was updated successfully, but these errors were encountered: