[PLUGIN] RotaryEncoder II

thanks for the guidelines, i will try and let you know.

I am using your plugin under Buster

  1. I am on volumio3
  2. I get the expected response

3.6) I get gibberish output on both terminals:

volumio@basscrab:~$ dtoverlay -l
Overlays (in load order):
0: rotary-encoder pin_a=5 pin_b=6 relative_axis=true steps-per-period=1
1: rotary-encoder pin_a=8 pin_b=9 relative_axis=true steps-per-period=1
volumio@basscrab:~$ dtoverlay -l
No overlays loaded
volumio@basscrab:~$ dtoverlay -l
No overlays loaded
volumio@basscrab:~$ sudo /usr/bin/dtoverlay rotary-encoder pin_a=5 pin_b=6 relative_axis=true steps-per-period=
volumio@basscrab:~$ sudo /usr/bin/dtoverlay rotary-encoder pin_a=8 pin_b=9 relative_axis=true steps-per-period=
volumio@basscrab:~$ dtoverlay -l
Overlays (in load order):
0: rotary-encoder pin_a=5 pin_b=6 relative_axis=true steps-per-period=1
1: rotary-encoder pin_a=8 pin_b=9 relative_axis=true steps-per-period=1
volumio@basscrab:~$ cat /dev/input/by-path/platform-rotary@5-event
�f�a
�f�a
�f�a�������f�a���f�a3�
�����f�a3�
�f�aߔ�����f�aߔ�f�aa>�����f�aa>�f�a�������f�a���f�a�~�����f�a�~�f�a�������f�a���f�a�������f�a���f�a�F �����f�a�F ug�ug�ug�a�▒ug�a�▒

volumio@basscrab:~$ cat /dev/input/by-path/platform-rotary@8-event
sg�a/�
sg�a/�
tg�a�����tg�a�tg�a�%
����tg�a�%
tg�a��
����tg�a��
vg�a<�����vg�a<�wg�a������wg�a��wg�a�q����wg�a�qwg�a7����wg�a7

Ok, looks good so far - so the dtoverlay behaves the same as in Jessie, it seems.
I also have built some hardware to test it (unfortunately have no loose rotaries flying around and do not want to dismantle my tube-radio, so I had to build something from some buttons I had).
I could only do some testing of the makeshift setup so far, but the command line response works with my test-setup. I will try to debug my code with it on Volumio 3 on the weekend.

If you want to do another test, you can decode the gibberish:
If you install the overlays as described above and pipe the cat output through od (octal dump) it becomes human-readable. But I expect you get similar results as mine below.
To pipe the output through od:

cat /dev/input/by-path/platform-rotary\@5-event | od -An -vx

When you turn the rotaries, you should get the event in hex format like this:

9848 61a6 35e2 000b 0002 0000 ffff ffff
9848 61a6 35e2 000b 0000 0000 0000 0000
9849 61a6 3515 000c 0002 0000 0001 0000
9849 61a6 3515 000c 0000 0000 0000 0000

The last four bytes are an unsigned representation for the direction: 0x0001 0000 = CW, 0xFFFF FFFF = CCW. (If you interpret it as a signed value, then it is -1, but the kernel docs list it as an unsigned - and who am I to argue with the Kernel docs :wink:.)
The 9-10th byte is the type of event, in this case 0x0002 means a turn of the rotary.
The first 8 bytes are a timeval, but this is not needed.
That all comes out correctly, so I suppose, something goes wrong in my interpretation code in V3 Buster, that worked in V2 Jessie.

Hi @T0MR0

I am too trying to get your plugin working with Volumio3.

Ive tried what Darmur suggest with recompiling the node modules and it all installs and activates OK from within Volumio 3

I set it up with the same settings which work perfectly in Volumio 2
In Volumio 3 the rotary does not work but the button does as it should.

Live log of the plugin being activated, settings entered, then saved.
I dont know if this has a bearing on the issue, but at the bottom of the log each time I save the settings an exit code 1 error appears. But this error wasnt there in Volumio 2 and the plugin works fine

Starting Live Log...
process exited with code nullinfo: [ROTARYENCODER2] deactivateButtons: button 1 is disabled.
info: [ROTARYENCODER2] getI18nString("TOAST_STOP_SUCCESS"):Plugin successfully stopped.
info: [ROTARYENCODER2] onStop: Plugin successfully stopped.
info: Disabling plugin rotaryencoder2
info: Done.
info: CALLMETHOD: system_controller system enableLiveLog true
info: CoreCommandRouter::executeOnPlugin: system , enableLiveLog
info: Launching a new LiveLog session
info: Killing previous LiveLog session
info: Live Log process terminated: null
info: CoreCommandRouter::executeOnPlugin: my_volumio , getMyVolumioStatus
info: CoreCommandRouter::executeOnPlugin: my_volumio , getMyVolumioToken
info: Enabling plugin rotaryencoder2
info: Loading plugin "rotaryencoder2"...
info: PLUGIN START: rotaryencoder2
info: [ROTARYENCODER2] loadI18nStrings: /data/plugins/user_interface/rotaryencoder2/i18n/strings_en.json
info: [ROTARYENCODER2] loadI18nStrings: loaded: {"ROTARYENCODER2":{"CONFIG":"Rotary Encoder II Plugin Configuration","SAVE":"Save","ENCODER0":"Rotary Encoder 1","D_ENCODER0":"Settings for the first rotary encoder.","ENCODER1":"Rotary Encoder 2","D_ENCODER1":"Settings for the second rotary encoder.","ENCODER2":"Rotary Encoder 3","D_ENCODER2":"Settings for the third rotary encoder.","ROTARYTYPE":"Periods per tick","D_ROTARYTYPE":"Periods per tick (Full: A and B full period, half: A and B half period, quarter: A or B half period","FULL":"Full-period mode","HALF":"Half-period mode","QUARTER":"Quarter-period mode","PINA":"Pin A GPIO","D_PINA":"GPIO pin that is connected to the first pin of the rotary.","PINB":"Pin B GPIO","D_PINB":"GPIO pin that is connected to the second pin of the rotary.","DIALACTION":"Dial Action","D_DIALACTION":"Action to be triggered by turning the rotary encocer. Option 'Emit Websocket Message' can be used to control other plugins using the Volumio Websock calls between Plugins. (see https://volumio.github.io/docs/API/WebSocket_APIs.html section 'CallMethod on Plugin' for details)","DOTS":"...","VOLUME":"Volume","SKIP":"Prev/Next title","SEEK":"Seek in title","SCROLL":"Scroll","EMIT":"Emit Websocket Message","SOCKCMDCCW":"Command CCW","SOCKDATACCW":"Data CCW","SOCKCMDCW":"Command CW","SOCKDATACW":"Data CW","SOCKCMD":"Command","SOCKDATA":"Data","D_SOCKCMD":"Command to send via Websocket","D_SOCKDATA":"Data to include with the Websocket Command","PINPUSH":"Pushbutton GPIO","D_PINPUSH":"GPIO pin that is connected to the pushbutton pin of the rotary. 0 or empty to disable.","PINPUSHDEBOUNCE":"Debounce-time (ms)","D_PINPUSHDEBOUNCE":"Debounce time for the button. If the button has hardware-debouncing, set to 0.","PUSHSTATE":"Button logic-level active low","D_PUSHSTATE":"Activate this, if pressing the button pulls the logic level on the GPIO low.","PUSHACTION":"Short Press Action","D_PUSHACTION":"Action that gets triggered, when pushbutton is pressed briefly.","LONGPUSHACTION":"Long Press Action","D_LONGPUSHACTION":"Action that gets triggered, when pushbutton is pressed longer.","SET_DEBUG":"Debug Settings","D_SET_DEBUG":"Settings for functional debugging.","PLAY":"Play","PAUSE":"Pause","PLAYPAUSE":"Play/Pause toggle","STOP":"Stop","REPEAT":"Repeat","RANDOM":"Random","CLEARQUEUE":"Clear Queue","MUTE":"Mute","UNMUTE":"Unmute","TOGGLEMUTE":"Toggle Mute","SHUTDOWN":"System Shutdown","REBOOT":"System Reboot","RESTARTAPP":"Restart Application","DUMPLOG":"Dump logfile","LOGGING":"Logging","D_LOGGING":"Switch the output of log messages on or off. Error messages are always logged.","TOAST_START_SUCCESS":"Plugin successfully started.","TOAST_STOP_SUCCESS":"Plugin successfully stopped.","TOAST_START_FAIL":"Plugins failed to start.","TOAST_STOP_FAIL":"Plugins failed to stop.","TOAST_GPIO_BLOCKED":"GPIO Pin unavailable","TOAST_MSG_OVERLAY_BLOCKING":"Blocked by another overlay.","TOAST_SAVE_SUCCESS":"Successfully saved","TOAST_MSG_SAVE":"Settings for Encoder ","TOAST_DEBUG_SAVE":"Debug Settings","TOAST_SAVE_FAIL":"Save failed","TOAST_WRONG_PARAMETER":"Error in parameters","TOAST_NEEDS_INTEGER":"GPIO Pins must be Integers.","TOAST_PINS_DIFFERENT":"GPIO Pins for A/B/Button must be different.","TOAST_PINS_BLOCKED":"Pins already used in another Encoder.","TOAST_NO_TYPE":"Please select 'Periods per tick'!"}}
info: [ROTARYENCODER2] onStart: Config loaded: {"syncSave":true,"autosave":true,"autosaveDelay":1000,"saved":true,"atomicSave":false,"data":{"enabled0":{"type":"boolean","value":true},"rotaryType0":{"type":"number","value":1},"pinA0":{"type":"string","value":"7"},"pinB0":{"type":"string","value":"8"},"dialAction0":{"type":"number","value":1},"socketCmdCW0":{"type":"string","value":""},"socketDataCW0":{"type":"string","value":""},"socketCmdCCW0":{"type":"string","value":""},"socketDataCCW0":{"type":"string","value":""},"pinPush0":{"type":"number","value":15},"pinPushDebounce0":{"type":"number","value":0},"pushState0":{"type":"boolean","value":true},"pushAction0":{"type":"number","value":3},"socketCmdPush0":{"type":"string","value":""},"socketDataPush0":{"type":"string","value":""},"longPushAction0":{"type":"number","value":0},"socketCmdLongPush0":{"type":"string","value":""},"socketDataLongPush0":{"type":"string","value":""},"enabled1":{"type":"boolean","value":false},"rotaryType1":{"type":"number","value":1},"pinA1":{"type":"string","value":"24"},"pinB1":{"type":"string","value":"26"},"dialAction1":{"type":"number","value":2},"socketCmdCW1":{"type":"string","value":""},"socketDataCW1":{"type":"string","value":""},"socketCmdCCW1":{"type":"string","value":""},"socketDataCCW1":{"type":"string","value":""},"pinPush1":{"type":"number","value":0},"pinPushDebounce1":{"type":"number","value":0},"pushState1":{"type":"boolean","value":false},"pushAction1":{"type":"number","value":0},"socketCmdPush1":{"type":"string","value":""},"socketDataPush1":{"type":"string","value":""},"longPushAction1":{"type":"number","value":0},"socketCmdLongPush1":{"type":"string","value":""},"socketDataLongPush1":{"type":"string","value":""},"enabled2":{"type":"boolean","value":false},"rotaryType2":{"type":"number","value":1},"pinA2":{"type":"string","value":"7"},"pinB2":{"type":"string","value":"8"},"dialAction2":{"type":"number","value":1},"socketCmdCW2":{"type":"string","value":""},"socketDataCW2":{"type":"string","value":""},"socketCmdCCW2":{"type":"string","value":""},"socketDataCCW2":{"type":"string","value":""},"pinPush2":{"type":"number","value":0},"pinPushDebounce2":{"type":"number","value":0},"pushState2":{"type":"boolean","value":false},"pushAction2":{"type":"number","value":0},"socketCmdPush2":{"type":"string","value":""},"socketDataPush2":{"type":"string","value":""},"longPushAction2":{"type":"number","value":0},"socketCmdLongPush2":{"type":"string","value":""},"socketDataLongPush2":{"type":"string","value":""},"logging":{"type":"boolean","value":true}},"callbacks":{"_":{}},"filePath":"/data/configuration/user_interface/rotaryencoder2/config.json"}
info: [ROTARYENCODER2] activateRotaries: 1,2,3
info: [ROTARYENCODER2] activateRotaries: 1,2
info: [ROTARYENCODER2] activateRotaries: 1
info: [ROTARYENCODER2] activateRotaries:
info: [ROTARYENCODER2] activateRotaries: end of recursion.
info: [ROTARYENCODER2] addOverlay: 7 8 1

 volumio : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/bin/dtoverlay rotary-encoder pin_a=7 pin_b=8 relative_axis=true steps-per-period=1
pam_unix(sudo:session): session opened for user root by (uid=0)
rotary-encoder rotary@7: gray
input: rotary@7 as /devices/platform/rotary@7/input/input5
pam_unix(sudo:session): session closed for user root
info: CoreCommandRouter::volumioGetState
info: CorePlayQueue::getTrack 0
info: [ROTARYENCODER2] attachListener: /dev/input/by-path/platform-rotary@7-event
info: [ROTARYENCODER2] addEventHandle for rotary: 1
info: [ROTARYENCODER2] activateButtons: 1,2,3
info: [ROTARYENCODER2] activateButtons: 1,2
info: [ROTARYENCODER2] activateButtons: 1
info: [ROTARYENCODER2] activateButtons:
info: [ROTARYENCODER2] activateButtons: end of recursion.
info: [ROTARYENCODER2] activateButtons: Now assign push button: 1
info: [ROTARYENCODER2] Push Button 1 now resolving.
info: [ROTARYENCODER2] onStart: Plugin successfully started.
info: Done.
Process '/usr/sbin/th-cmd --socket /var/run/thd.socket --passfd --udev' failed with exit code 1.
info: CoreCommandRouter::getUIConfigOnPlugin
info: [ROTARYENCODER2] getUIConfig: starting:
info: [ROTARYENCODER2] getUIConfig: i18nStrings{"ROTARYENCODER2":{"CONFIG":"Rotary Encoder II Plugin Configuration","SAVE":"Save","ENCODER0":"Rotary Encoder 1","D_ENCODER0":"Settings for the first rotary encoder.","ENCODER1":"Rotary Encoder 2","D_ENCODER1":"Settings for the second rotary encoder.","ENCODER2":"Rotary Encoder 3","D_ENCODER2":"Settings for the third rotary encoder.","ROTARYTYPE":"Periods per tick","D_ROTARYTYPE":"Periods per tick (Full: A and B full period, half: A and B half period, quarter: A or B half period","FULL":"Full-period mode","HALF":"Half-period mode","QUARTER":"Quarter-period mode","PINA":"Pin A GPIO","D_PINA":"GPIO pin that is connected to the first pin of the rotary.","PINB":"Pin B GPIO","D_PINB":"GPIO pin that is connected to the second pin of the rotary.","DIALACTION":"Dial Action","D_DIALACTION":"Action to be triggered by turning the rotary encocer. Option 'Emit Websocket Message' can be used to control other plugins using the Volumio Websock calls between Plugins. (see https://volumio.github.io/docs/API/WebSocket_APIs.html section 'CallMethod on Plugin' for details)","DOTS":"...","VOLUME":"Volume","SKIP":"Prev/Next title","SEEK":"Seek in title","SCROLL":"Scroll","EMIT":"Emit Websocket Message","SOCKCMDCCW":"Command CCW","SOCKDATACCW":"Data CCW","SOCKCMDCW":"Command CW","SOCKDATACW":"Data CW","SOCKCMD":"Command","SOCKDATA":"Data","D_SOCKCMD":"Command to send via Websocket","D_SOCKDATA":"Data to include with the Websocket Command","PINPUSH":"Pushbutton GPIO","D_PINPUSH":"GPIO pin that is connected to the pushbutton pin of the rotary. 0 or empty to disable.","PINPUSHDEBOUNCE":"Debounce-time (ms)","D_PINPUSHDEBOUNCE":"Debounce time for the button. If the button has hardware-debouncing, set to 0.","PUSHSTATE":"Button logic-level active low","D_PUSHSTATE":"Activate this, if pressing the button pulls the logic level on the GPIO low.","PUSHACTION":"Short Press Action","D_PUSHACTION":"Action that gets triggered, when pushbutton is pressed briefly.","LONGPUSHACTION":"Long Press Action","D_LONGPUSHACTION":"Action that gets triggered, when pushbutton is pressed longer.","SET_DEBUG":"Debug Settings","D_SET_DEBUG":"Settings for functional debugging.","PLAY":"Play","PAUSE":"Pause","PLAYPAUSE":"Play/Pause toggle","STOP":"Stop","REPEAT":"Repeat","RANDOM":"Random","CLEARQUEUE":"Clear Queue","MUTE":"Mute","UNMUTE":"Unmute","TOGGLEMUTE":"Toggle Mute","SHUTDOWN":"System Shutdown","REBOOT":"System Reboot","RESTARTAPP":"Restart Application","DUMPLOG":"Dump logfile","LOGGING":"Logging","D_LOGGING":"Switch the output of log messages on or off. Error messages are always logged.","TOAST_START_SUCCESS":"Plugin successfully started.","TOAST_STOP_SUCCESS":"Plugin successfully stopped.","TOAST_START_FAIL":"Plugins failed to start.","TOAST_STOP_FAIL":"Plugins failed to stop.","TOAST_GPIO_BLOCKED":"GPIO Pin unavailable","TOAST_MSG_OVERLAY_BLOCKING":"Blocked by another overlay.","TOAST_SAVE_SUCCESS":"Successfully saved","TOAST_MSG_SAVE":"Settings for Encoder ","TOAST_DEBUG_SAVE":"Debug Settings","TOAST_SAVE_FAIL":"Save failed","TOAST_WRONG_PARAMETER":"Error in parameters","TOAST_NEEDS_INTEGER":"GPIO Pins must be Integers.","TOAST_PINS_DIFFERENT":"GPIO Pins for A/B/Button must be different.","TOAST_PINS_BLOCKED":"Pins already used in another Encoder.","TOAST_NO_TYPE":"Please select 'Periods per tick'!"}}
info: [ROTARYENCODER2] getUIConfig: i18nStringsDefaults{"ROTARYENCODER2":{"CONFIG":"Rotary Encoder II Plugin Configuration","SAVE":"Save","ENCODER0":"Rotary Encoder 1","D_ENCODER0":"Settings for the first rotary encoder.","ENCODER1":"Rotary Encoder 2","D_ENCODER1":"Settings for the second rotary encoder.","ENCODER2":"Rotary Encoder 3","D_ENCODER2":"Settings for the third rotary encoder.","ROTARYTYPE":"Periods per tick","D_ROTARYTYPE":"Periods per tick (Full: A and B full period, half: A and B half period, quarter: A or B half period","FULL":"Full-period mode","HALF":"Half-period mode","QUARTER":"Quarter-period mode","PINA":"Pin A GPIO","D_PINA":"GPIO pin that is connected to the first pin of the rotary.","PINB":"Pin B GPIO","D_PINB":"GPIO pin that is connected to the second pin of the rotary.","DIALACTION":"Dial Action","D_DIALACTION":"Action to be triggered by turning the rotary encocer. Option 'Emit Websocket Message' can be used to control other plugins using the Volumio Websock calls between Plugins. (see https://volumio.github.io/docs/API/WebSocket_APIs.html section 'CallMethod on Plugin' for details)","DOTS":"...","VOLUME":"Volume","SKIP":"Prev/Next title","SEEK":"Seek in title","SCROLL":"Scroll","EMIT":"Emit Websocket Message","SOCKCMDCCW":"Command CCW","SOCKDATACCW":"Data CCW","SOCKCMDCW":"Command CW","SOCKDATACW":"Data CW","SOCKCMD":"Command","SOCKDATA":"Data","D_SOCKCMD":"Command to send via Websocket","D_SOCKDATA":"Data to include with the Websocket Command","PINPUSH":"Pushbutton GPIO","D_PINPUSH":"GPIO pin that is connected to the pushbutton pin of the rotary. 0 or empty to disable.","PINPUSHDEBOUNCE":"Debounce-time (ms)","D_PINPUSHDEBOUNCE":"Debounce time for the button. If the button has hardware-debouncing, set to 0.","PUSHSTATE":"Button logic-level active low","D_PUSHSTATE":"Activate this, if pressing the button pulls the logic level on the GPIO low.","PUSHACTION":"Short Press Action","D_PUSHACTION":"Action that gets triggered, when pushbutton is pressed briefly.","LONGPUSHACTION":"Long Press Action","D_LONGPUSHACTION":"Action that gets triggered, when pushbutton is pressed longer.","SET_DEBUG":"Debug Settings","D_SET_DEBUG":"Settings for functional debugging.","PLAY":"Play","PAUSE":"Pause","PLAYPAUSE":"Play/Pause toggle","STOP":"Stop","REPEAT":"Repeat","RANDOM":"Random","CLEARQUEUE":"Clear Queue","MUTE":"Mute","UNMUTE":"Unmute","TOGGLEMUTE":"Toggle Mute","SHUTDOWN":"System Shutdown","REBOOT":"System Reboot","RESTARTAPP":"Restart Application","DUMPLOG":"Dump logfile","LOGGING":"Logging","D_LOGGING":"Switch the output of log messages on or off. Error messages are always logged.","TOAST_START_SUCCESS":"Plugin successfully started.","TOAST_STOP_SUCCESS":"Plugin successfully stopped.","TOAST_START_FAIL":"Plugins failed to start.","TOAST_STOP_FAIL":"Plugins failed to stop.","TOAST_GPIO_BLOCKED":"GPIO Pin unavailable","TOAST_MSG_OVERLAY_BLOCKING":"Blocked by another overlay.","TOAST_SAVE_SUCCESS":"Successfully saved","TOAST_MSG_SAVE":"Settings for Encoder ","TOAST_DEBUG_SAVE":"Debug Settings","TOAST_SAVE_FAIL":"Save failed","TOAST_WRONG_PARAMETER":"Error in parameters","TOAST_NEEDS_INTEGER":"GPIO Pins must be Integers.","TOAST_PINS_DIFFERENT":"GPIO Pins for A/B/Button must be different.","TOAST_PINS_BLOCKED":"Pins already used in another Encoder.","TOAST_NO_TYPE":"Please select 'Periods per tick'!"}}
info: [ROTARYENCODER2] getUIConfig: language code: en dir: /data/plugins/user_interface/rotaryencoder2
info: [ROTARYENCODER2] getI18nString("VOLUME"):Volume
info: [ROTARYENCODER2] getI18nString("PLAYPAUSE"):Play/Pause toggle
info: [ROTARYENCODER2] getI18nString("DOTS"):...
info: [ROTARYENCODER2] getI18nString("SKIP"):Prev/Next title
info: [ROTARYENCODER2] getI18nString("DOTS"):...
info: [ROTARYENCODER2] getI18nString("DOTS"):...
info: [ROTARYENCODER2] getI18nString("VOLUME"):Volume
info: [ROTARYENCODER2] getI18nString("DOTS"):...
info: [ROTARYENCODER2] getI18nString("DOTS"):...
info: CALLMETHOD: user_interface rotaryencoder2 updateEncoder [object Object]
info: CoreCommandRouter::executeOnPlugin: rotaryencoder2 , updateEncoder
info: [ROTARYENCODER2] updateEncoder: Rotary1 with:{"enabled0":true,"rotaryType0":{"value":1,"label":"1/1"},"pinA0":7,"pinB0":8,"dialAction0":{"value":1,"label":"Volume"},"socketCmdCCW0":"","socketDataCCW0":"","socketCmdCW0":"","socketDataCW0":"","pinPush0":15,"pinPushDebounce0":0,"pushState0":true,"pushAction0":{"value":3,"label":"Play/Pause toggle"},"socketCmdPush0":"","socketDataPush0":"","longPushAction0":{"value":0,"label":"..."},"socketCmdLongPush0":"","socketDataLongPush0":""}
info: [ROTARYENCODER2] sanityCheckSettings: Rotary1 for:{"enabled0":true,"rotaryType0":{"value":1,"label":"1/1"},"pinA0":7,"pinB0":8,"dialAction0":{"value":1,"label":"Volume"},"socketCmdCCW0":"","socketDataCCW0":"","socketCmdCW0":"","socketDataCW0":"","pinPush0":15,"pinPushDebounce0":0,"pushState0":true,"pushAction0":{"value":3,"label":"Play/Pause toggle"},"socketCmdPush0":"","socketDataPush0":"","longPushAction0":{"value":0,"label":"..."},"socketCmdLongPush0":"","socketDataLongPush0":""}
info: [ROTARYENCODER2] deactivateRotaries: 1,2,3
info: [ROTARYENCODER2] deactivateRotaries: 2,3
info: [ROTARYENCODER2] deactivateRotaries: 3
info: [ROTARYENCODER2] deactivateRotaries:
info: [ROTARYENCODER2] deactivateRotaries: end of recursion.
info: [ROTARYENCODER2] detachListener: [object Object]
info: [ROTARYENCODER2] checkOverlayExists: Checking for existing overlays for Rotary: 1
 volumio : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/bin/dtoverlay -l
pam_unix(sudo:session): session opened for user root by (uid=0)
pam_unix(sudo:session): session closed for user root
info: [ROTARYENCODER2] checkOverlayExists: check pinA=7pinB=8 in Overlays (in load order):
0:  rotary-encoder  pin_a=7 pin_b=8 relative_axis=true steps-per-period=1
info: [ROTARYENCODER2] checkOverlayExists: rotary 1uses overlay 0
info: [ROTARYENCODER2] removeOverlay: 0
 volumio : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/bin/dtoverlay -r 0
pam_unix(sudo:session): session opened for user root by (uid=0)
pam_unix(sudo:session): session closed for user root
info: [ROTARYENCODER2] removeOverlay: 0 returned:
 volumio : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/bin/dtoverlay -l
pam_unix(sudo:session): session opened for user root by (uid=0)
pam_unix(sudo:session): session closed for user root
info: [ROTARYENCODER2] removeOverlay: "overlay -l" returned: No overlays loaded
info: [ROTARYENCODER2] deactivateRotaries: deactivated rotary1
info: [ROTARYENCODER2] deactivateButtons: 1,2,3
info: [ROTARYENCODER2] deactivateButtons: 2,3
info: [ROTARYENCODER2] deactivateButtons: 3
info: [ROTARYENCODER2] deactivateButtons:
info: [ROTARYENCODER2] deactivateButtons: end of recursion.
info: [ROTARYENCODER2] deactivateButtons: button 1 is disabled.
info: [ROTARYENCODER2] updateEncoder: Changing Encoder 1 Settings to new values
info: [ROTARYENCODER2] activateRotaries: 1,2,3
info: [ROTARYENCODER2] activateRotaries: 1,2
info: [ROTARYENCODER2] activateRotaries: 1
info: [ROTARYENCODER2] activateRotaries:
info: [ROTARYENCODER2] activateRotaries: end of recursion.
info: [ROTARYENCODER2] addOverlay: 7 8 1
 volumio : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/bin/dtoverlay rotary-encoder pin_a=7 pin_b=8 relative_axis=true steps-per-period=1
pam_unix(sudo:session): session opened for user root by (uid=0)
rotary-encoder rotary@7: gray
input: rotary@7 as /devices/platform/rotary@7/input/input6
pam_unix(sudo:session): session closed for user root
info: [ROTARYENCODER2] attachListener: /dev/input/by-path/platform-rotary@7-event
info: [ROTARYENCODER2] addEventHandle for rotary: 1
info: [ROTARYENCODER2] activateButtons: 1,2,3
info: [ROTARYENCODER2] activateButtons: 1,2
info: [ROTARYENCODER2] activateButtons: 1
info: [ROTARYENCODER2] activateButtons:
info: [ROTARYENCODER2] activateButtons: end of recursion.
info: [ROTARYENCODER2] activateButtons: Now assign push button: 1
info: [ROTARYENCODER2] Push Button 1 now resolving.
info: [ROTARYENCODER2] getI18nString("TOAST_SAVE_SUCCESS"):Successfully saved
info: [ROTARYENCODER2] getI18nString("TOAST_MSG_SAVE"):Settings for Encoder
info: [ROTARYENCODER2] updateEncoder: SUCCESS with Toast: Successfully saved Settings for Encoder 1
info: [ROTARYENCODER2] getI18nString("TOAST_SAVE_SUCCESS"):Successfully saved
info: [ROTARYENCODER2] getI18nString("TOAST_MSG_SAVE"):Settings for Encoder
Process '/usr/sbin/th-cmd --socket /var/run/thd.socket --passfd --udev' failed with exit code 1.

With the plugin enabled from an SSH window I issued the cat /dev/input/by-path/platform-rotary\@7-event | od -An -vx command and the rotary was giving an output OK. CW then ACW


 5cf1 61a7 ce51 000a 0000 0000 0000 0000
 5cf1 61a7 c286 000b 0002 0000 0001 0000
 5cf1 61a7 c286 000b 0000 0000 0000 0000
 5cf1 61a7 a179 000c 0002 0000 0001 0000
 5cf1 61a7 a179 000c 0000 0000 0000 0000
 5cf1 61a7 da0c 000d 0002 0000 0001 0000
 5cf1 61a7 da0c 000d 0000 0000 0000 0000
 5cf2 61a7 4d04 0002 0002 0000 ffff ffff
 5cf2 61a7 4d04 0002 0000 0000 0000 0000
 5cf2 61a7 226e 0003 0002 0000 ffff ffff
 5cf2 61a7 226e 0003 0000 0000 0000 0000
 5cf2 61a7 a753 0003 0002 0000 ffff ffff
 5cf2 61a7 a753 0003 0000 0000 0000 0000
 5cf2 61a7 156a 0004 0002 0000 ffff ffff

Hardware RPI4 2GB, D10 Dac

Hope this will help, any other test needed just ask, I’ll try

1 Like

Hi M1ck!
Thanks! I already figured out, that it is related to the child process which handles the rotary device. It does not work anymore in Buster.
It is probably easy to fix, but I need a few hours to sit down, Test and implement. Hope to be able to do that on the weekend.
I‘ll post a Link to a fixed package for Testing asap.
Please be patient!

1 Like

another update - there seems to be a thing called “trigger happy daemon” which somehow attaches to all devices - when I kill that process, it partly works again. But I still need some more cleaning up and need to figure out, what trigger happy is used for and how to keep it from grabbing the rotary

thd is utilised for input handling for remotes/keyboards etc.
You might be able to simplify your plugin by hooking into it directly, once the encoders are configured properly.

Faster alternative - you could add your encoders to it’s avoid list

--ignore eventname
           Ignore key and switch event labeled eventname. This can be used to suppress the FN key
           on some notebooks which only generates events sometimes and might screw up key
           combinations.

EDIT:
I looked (very quickly) at your plugin, and see that you spawn a process to read /dev/input/by-path/platform-rotary\@<>-event - have a look at Node’s readstream that can do this for you, without the overhead of the process spawning :slight_smile:

For usual NEXT/PREV/Volume, you can hook into triggerhappy directly. For the generic generic websocket event, you could also do the same, but would need to be a bit more creative. Not sure if it yields any benefits though.

1 Like

Thanks, I’ll explore thd a bit the next days.

My first version of the plugin was initially using readStream but I had to abandon that, because I could not get the handle properly released, which created issues with stopping and restarting the plugin. I even posted to the node issues on Github about it but in the end followed the workaround proposed at the end of this thread. After weeks of debugging, that was the only option that allowed a proper release and subsequent removal of the overlay.

When I dug out my old post up now, I see that this problem is mentioned in the documentation of fs now and there is a new proposal to close the stream with stream.push(null). I’ll try that the next days and see, if I can move back to the readStream and abandon the spawn-crutch.

2 Likes

Hi Darmur

I tried to install the rotary II plugin on Volumio 3 according to your proposal…
Once i get to the “npm install --save onoff@6.0.0” get the following:

In the end the pushbutton is working but the rotary encoder is not. With Volumio 2.X it did work…
Can you tell me what is the problem?
Thanks for your help

This is exactly what happens to me.
The author T0MR0 is looking into why it no longer works with V3
We need to be patient

Hi all,
sorry - still very busy times for me. Had a little time to dig and play and build a first fix.
Here is my current hypthesis:

  • In buster, we have the triggerhappy-daemon thd, which is watching the /dev/input folder for new devices. However, triggerhappy is not aware of rotary-encoders, so it does not act on the new device but seems to slow the udev process a bit.
  • I will not move to triggerhappy as was suggested, because it currently does not support rotary encoders and I do not like the idea of building on code, that seems to be abandoned since 2016. There is an open pull-request to include rotaries here which seems to be merged into another package in the meantime - but overall I trust the approach to build on Linux base-functionality more, as it works and is easier to maintain.
  • I also noticed, that dtoverlay returns before the by-path reference to the rotary is available to the system, because it is made with some delay by udev. Therefore the event-handle is not properly configured, which leads to the malfunction of one of the encoders.
  • As a first quick fix, to give all of you a work-around, I have installed a timeout to delay the activation of the events. This solves the issue on my test-system, giving me two functional encoders.
  • I uploaded a package in a branch on my personal repo. It was made with volumio plugin package on my Buster test-system. You should be able to use it and do a test. Let me know, how it goes. package is here
  • For a permanent fix I want to try and significantly improve the code. I think I found a way, to go back to readstream, but I need to test if it really does not crash the system anymore like in my old implementation, where it sometimes waited for data indefinitely. I also would like to insert a function that verifies, that the by-path reference is really installed, before it resolves the promise. Hope I have some time over the Holidays.
3 Likes

Hi @T0MR0

Just tested
Only using the 1 encoder as the volume, which seems to be working just fine.

You should submit it to the volumio plugin store as a beta, this will let other people have an encoder, while you work on getting it the way you want it to be.

Thanks BTW and good job :+1:

1 Like

I just submitted the patched version to the repo and created a pull request.
Hope this works, not 100% sure if I correctly followed the new Volumio 3 submission process. Let’s see, what the Jury says…
If I did not make a major mistake, you may be able to see it on the Beta Channel soon.

Hi T0MR0

The new version is working on my system as well, thank you!

1 Like

It is working I can confirm as well. Perfect job!

1 Like

Hi T0MR0

I have a strange behavior with the newest Rotary encoder version…It seems to be related with my Hifiberry DAC2 HD.
When Install the plugin and set the rotary to volume everything works fine. when I restart the system the sound is still there, but it when the startup is completed the sound dissapears. When i go into the Plugin setup and switch the rotary back to for example to track forward / backwards the sound comes back after saving. If I then switch back the rotary to Volume everything works fine until the next startup…
Do you have any Idea what could be the problem?
Thanks for your Help
Waldi

Hi Waldi, sorry to hear that, but I need a bit more info:

  • Which version are you referring to? 1.0.8 for Volumio3 or the version on the Volumio2 Plug-in Store?
  • Which Volumio version are U on?
  • Are you using any of GPIO2,3,16,18-21 for your rotaries?
  • Can you generate a log file?
  • I am using two kinds of Hifiberries without issues… and they use the same GPIOs as the HD.
    I need more info for a hypothesis…
    Regards Thomas
1 Like

it works like a charm with two encoders on Buster, well done!

Are you planning to publish it on the Volumio3 plugin store?

Hi, the PR is pending, see Here

Hi Thomas

Thanks for your answer…

I am referring to 1.0.8 for Volumio 3 and I am using it on Volumio 3. I use GIPIO 27 for the pushbutton and GPIO 17 and 22 for the rotary. I am actually sure that I did not mess up with the GPIOS of the Hifiberry …because the same setup with Volumio 2.9xx and the RotaryII decoder form the plugin store worked fine.
Ill try to make a log, I’ve never done one but I remember that it was described earlier in this post…Just needs some time…
Thanks for your Help

Christoph