eltariel / njak

Driver software for buttons and lights a la Pimoroni Keybow
GNU General Public License v3.0
0 stars 0 forks source link

Some errors while / after install #2

Open Olfried2 opened 3 years ago

Olfried2 commented 3 years ago

Hello elrariel, today I got my raspi W and immediatly prepared a sd-card with latest Dietpi. I had some trouble following your "installation" hints, but I got it so far. I installed everything in /opt/nkjack-master/. I made the "systemd"-stuff When I started the init-usb-gadgets.sh shell I got the following errors oot@DietPi:/opt/njak-master# ./init-usb-gadgets.sh cat: /opt/njak-master/descriptors/mac-dev: No such file or directory cat: /opt/njak-master/descriptors/mac-host: No such file or directory njak: Loading libcomposite njak: Creating njak ./init-usb-gadgets.sh: line 32: echo: write error: No such device njak: Setting USB properties njak: Creating config ln: failed to create symbolic link '/sys/kernel/config/usb_gadget/njak/os_desc/c.1': File exists njak: Registering RNDIS ./init-usb-gadgets.sh: line 62: echo: write error: Device or resource busy ./init-usb-gadgets.sh: line 63: echo: write error: Device or resource busy ln: failed to create symbolic link '/sys/kernel/config/usb_gadget/njak/configs/c.1/rndis.0': File exists njak: Registering HID using /opt/njak-master/descriptors/bootkbd.bin for Boot Keyboard Descriptor ./init-usb-gadgets.sh: line 73: echo: write error: Device or resource busy ./init-usb-gadgets.sh: line 74: echo: write error: Device or resource busy ./init-usb-gadgets.sh: line 75: echo: write error: Device or resource busy cat: write error: Device or resource busy ln: failed to create symbolic link '/sys/kernel/config/usb_gadget/njak/configs/c.1/hid.0': File exists njak: Registering HID using /opt/njak-master/descriptors/ext_hid.bin for Extended Keyboard Descriptor ./init-usb-gadgets.sh: line 81: echo: write error: Device or resource busy ./init-usb-gadgets.sh: line 82: echo: write error: Device or resource busy ./init-usb-gadgets.sh: line 83: echo: write error: Device or resource busy cat: write error: Device or resource busy ln: failed to create symbolic link '/sys/kernel/config/usb_gadget/njak/configs/c.1/hid.1': File exists njak: Registering MIDI ln: failed to create symbolic link '/sys/kernel/config/usb_gadget/njak/configs/c.1/midi.0': File exists njak: Registering ACM ln: failed to create symbolic link '/sys/kernel/config/usb_gadget/njak/configs/c.1/acm.0': File exists njak: Enabling gadget njak: njak Created As I saw that most of the errors are 'file exists' I just continued.

But after starting python3 /opt/njak-master/njak.py I got a more detailed errormessage - which I don't understand and where I don't know how to solve.

root@DietPi:~# python3 /opt/njak-master/njak.py Traceback (most recent call last): File "/opt/njak-master/njak.py", line 59, in <module> n = Njak(c) File "/opt/njak-master/njak.py", line 16, in __init__ self.lights = leds.Lights(config.ledmap) File "/opt/njak-master/leds.py", line 82, in __init__ self.spi.open(0, 0) FileNotFoundError: [Errno 2] No such file or directory

Any hints what to do ? TIA (I cannot upload a freemind .mm file even when I give them a different extension)

eltariel commented 3 years ago

Ok, so the init-usb-gadgets.sh issue appears to be either that you don't have the pi set up in USB gadget mode, or that something else has claimed the gadget controller before you can get to it (could even have been a previous run of the script, it doesn't clean up after itself). Don't worry too much about the lines complaining about mac-dev and mac-host, they're for customising the ethernet device and it works fine without them.

The one for python3 error is likely that you don't have the SPI device enabled.

Both of these are usually solved by editing /boot/config.txt on raspberry pi os, I assume dietpi uses the same configuration. You will need to add the following lines and then reboot:

dtoverlay=dwc2
dtparam=spi=on

If making these changes don't solve things, then it's possible that the dietpi kernel doesn't include the modules we need for this to work.

eltariel commented 3 years ago

I've updated the readme with some of these additional setup steps. Let me know if this solves your issue 😀

Olfried2 commented 3 years ago

Thanks for the readme update! - and sorry for the delay, answering.

Something is working something not I got the keyBo running (all LEDs are making nervous colorchanges) when I press a key, nothing happens on my receiving machine but the raspberry - python throws a lot of informations\

Attempting to write a HID report: bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/pins/rpigpio.py", line 244, in _call_when_changed
    super(RPiGPIOPin, self)._call_when_changed()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/pins/local.py", line 143, in _call_when_changed
    self.state if state is None else state)
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/pins/pi.py", line 293, in _call_when_changed
    method(ticks, state)
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/input_devices.py", line 197, in _pin_changed
    self._fire_events(ticks, bool(self._state_to_value(state)))
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 368, in _fire_events
    self._fire_activated()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 397, in _fire_activated
    super(HoldMixin, self)._fire_activated()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 344, in _fire_activated
    self.when_activated()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 334, in wrapper
    return fn(self)
  File "/opt/njak-master/keys.py", line 41, in _handler
    self.handler(button, self)
  File "/opt/njak-master/keys.py", line 90, in _key_handler
    self.layers[self.current_layer][key.num - 1](button, key)
  File "/opt/njak-master/hid/bitmap_report.py", line 81, in _handle_key_code
    self.send()
  File "/opt/njak-master/hid/bitmap_report.py", line 56, in send
    self.gadget.send_report(self._buf)
  File "/opt/njak-master/hid/gadget.py", line 26, in send_report
    gadget.write(report_bytes)
BrokenPipeError: [Errno 108] Cannot send after transport endpoint shutdown
Keycode 97 released
Attempting to write a HID report: bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/pins/rpigpio.py", line 244, in _call_when_changed
    super(RPiGPIOPin, self)._call_when_changed()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/pins/local.py", line 143, in _call_when_changed
    self.state if state is None else state)
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/pins/pi.py", line 293, in _call_when_changed
    method(ticks, state)
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/input_devices.py", line 197, in _pin_changed
    self._fire_events(ticks, bool(self._state_to_value(state)))
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 372, in _fire_events
    self._fire_deactivated()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 402, in _fire_deactivated
    super(HoldMixin, self)._fire_deactivated()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 349, in _fire_deactivated
    self.when_deactivated()
  File "/usr/local/lib/python3.7/dist-packages/gpiozero/mixins.py", line 334, in wrapper
    return fn(self)
  File "/opt/njak-master/keys.py", line 41, in _handler
    self.handler(button, self)
  File "/opt/njak-master/keys.py", line 90, in _key_handler
    self.layers[self.current_layer][key.num - 1](button, key)
  File "/opt/njak-master/hid/bitmap_report.py", line 85, in _handle_key_code
    self.send()
  File "/opt/njak-master/hid/bitmap_report.py", line 56, in send
    self.gadget.send_report(self._buf)
  File "/opt/njak-master/hid/gadget.py", line 26, in send_report
    gadget.write(report_bytes)
BrokenPipeError: [Errno 108] Cannot send after transport endpoint shutdown

But nothing appears on the "receiving machine". Any hints ? And where can I disable the "Lightshow" It's hard to concentrate beside this flickering thing :)

eltariel commented 3 years ago

Easy thing first: Currently you can disable the lightshow by editing the Njak.loop() method in njak.py. There's no real config for it at this point (it's coming eventually!)

The less easy thing: The line Attempting to write a HID report is njak sending a HID report to the gadget device. This usually fails with this error if there's something wrong with the connection on the host computer, it's probably tried to disconnect from the device for some reason. I've seen this on windows hosts a number of times if the gadget config script isn't run early enough because windows seems to like caching USB descriptors. Check what you see on the windows host, maybe re-enable the device if it's disabled and possibly scan for hardware changes. If there's anything else on the same USB port try moving the pi to its own dedicated root port (i.e. on the computer not a hub) and see what happens.

Olfried2 commented 3 years ago

Oh,oh,oh how embarrasing - I used a usb cable with a switch (it looks like usb, but it's only a cable with two usb plugs) I found myself in the kernel..usb HID manual watching to solve my problem but it was sooo easy, just change to a proven data usb cable.

BTW, I didn't see a "name" in lsusb . I think the blank entry is the keyboo.

Stopping the lightshow was relatively easy. Couldn't you define a variable on top of the code to enable or disable these program part? ... but see my follwing mesg.

The keys also work on Windows 10 home.

question: would it be possible to have the program read the settings from a "config file"? I'm just working on a sketch of a local webserver (php -S..) to have a page where you can set the keys more comfortable.

Which brings me to the next question, where and how the key-values and the LED's are described? I think I'll edit a "config" file via php (because that's a language I know better than python) and than do a "system" with reboot or just restart the njak program. I would like to do this in python also, but all I found was "django" and "REST" which seems to be an overkill to use a framework for just a configuration page.

eltariel commented 3 years ago

There is already a configuration file: config.py defines a configuration object which currently contains pin mappings for the buttons and not much else. This would be a logical place for an option to define lighting and keymaps.

Key behaviour is currently declared in the njak class constructor, but don't get too attached to that because I have made some significant changes to the way the code is structured and they won't be there when I get around to meeting those changes.

As for a web UI - it'd be better to create a rest API to do the configuration, and separate the UI into its own process. Or an app on another computer. This was way down on my list of things to get around to, but it's there.

Olfried2 commented 3 years ago

YO, there is (sorry) something in the config.py file (reordered)

    (0, 20),
    (1, 6),
    (2, 22),
    (3, 17),
    (4, 16),
    (5, 12),
    (6, 24),
    (7, 27),
    (8, 26),
    (9, 13),
    (10, 5),
    (11, 23),
]

But opposite to you example in the readme, here are only 2 values and your comment says

layout: list of (led position, gpio pin) for each key. io_mapping[n] represents the nth key.

Where do I add the Text or the char or the keycombination ?

Sorry, but I can't follow (understand) the python-code I'm always lookong for a main() I agree, it would be nice to have a REST API, maybe this could be a good training for me for my further python-programming career ;). But at the moment I'm looking for a fast way to get "programming" njak solved. And in my investigation, there's no problem running the php server on the pi.

eltariel commented 3 years ago

Long story short: there is no 'main' function.

In python the 'main' function is just a convention. The actual entry point for a script is the top of the file. If the file is executed directly rather than imported, it will have the __name__ variable set to the special value __main__, so usually anything other than definitions usually gets put at the end of the script file in a block like this:

if __name__ == '__main__':
    do_things()
    do_other_things()

It's also not uncommon to define a method called main(). Bear in mind that defining a method does nothing on its own, and you still need to call it like this:

def main():
    do_stuff()
    do_other_stuff()

if __name__ == '__main__':
    main()

In njak.py I didn't use a main() function. The logic runs directly from inside the if block: it creates an instance of the config class and the Njak class, then runs an infinite loop which calls the loop() method on the Njak object.

The key behaviours are defined in Njak.__init__(). It's a bit of a mess at this point and I'm working on it as I write this, but the current setup matches what is described in the readme:

The order of these keys matches the layout array from config.py - that's the hardware layout, not the key mapping. If you change the order of those entries, the LED and the key will still operate together, but the order of the keys on the keypad will not match the order of things defined in your layers.


If you want to help make this configurable, I would suggest the following points:

  1. Decide how the device should behave: what should each key do? No need to get fancy just yet, we can extend it later.
  2. Figure out how to represent the state of the device, and how to map it to a REST API. Probably look into OpenAPI/Swagger and then we can generate a lot of the code from that 😀
  3. Build that API into njak - bear in mind that it doesn't actually have to do anything straight away, we can hook it all together as we go
  4. Build whatever web frontend you want in whatever language suits you.

Whatever you do, don't attempt to directly manipulate the config files from your web frontend. That's a great way to have everything break as soon as part of the code changes 😛