Raspberry pi autostart command for USB serial?

I’m having trouble getting a script working. I’m using manjaro 23.02 64 on raspberry pi 4 B.
I have placed a file named raspberry.conf in /etc/modprobe.d containing “dwc2”.
I added “dtoverlay=dwc2,dr_mode=host” to the config.txt.
I can now start a fan on an external adapter with a terminal command:

sudo sh -c "echo pwm_100 > /dev/ttyUSB0"

I can’t seem to get it to work at boot or login with a script.
I have an extremely simple bash script at /etc/systemd/scripts/startfan.sh containing the bash line and the above command.
I have a service file at /lib/systemd/system/startfan.service containing the following:

[Unit]
Description=blabla
After=dev.ttyUSB0.device

[Service]
Type=Simple
ExecStart=/etc/systemd/scripts/startfan.sh

[Install]
WantedBy=multi-user.target

I have tried changing ownership and permissions to root for both files and removing the “sudo.”
I’ve tried using a .desktop file (running gnome 40) in my autostart folder and adding a sudoers NOPASSWD line for the script (when it has user ownership and permissions).
I’ve done the “systemctl enable” command for the .service file without errors.
I’m not sure where to look for logs or how to add them.
I have had success with this working in debian based systems but I’m very partial to the modern feel and otherwise better usability/compatibility of manjaro.
EDIT: I should add that when I start the fan using the terminal command it will stay on completely through a reboot but will not start when the pi is powered off and then powered back on.
What am I missing?

Thanks.

It’s been a while since I used arm, but this doesn’t seem arm specific.

I assume you haven’t got any more serial devices, because if you do, you might not be able to guarantee you have the right device when using /dev/ttyUSB0.

Add yourself to the uucp group and you won’t need root.

sudo gpasswd -a $USER uucp

That should be in /usr/local/bin, but I don’t think it’s needed anyway. If it is needed, then to match the service file it should look like this:

#!/usr/bin/bash
echo pwm_100 > /dev/ttyUSB0

And saved as /usr/local/bin/startfan, don’t forget to change the ExecStart= line.

That should be in /etc/systemd/system

They should be owned by root.


What does systemctl status startfan say?

A few ideas to try:

  1. Cut out the middle man.
# /etc/systemd/systemd/startfan.service
[Unit]
Description=blabla
After=dev.ttyUSB0.device

[Service]
Type=oneshot
ExecStart=/usr/bin/echo pwm_100 > /dev/ttyUSB0

[Install]
WantedBy=multi-user.target
  1. Try WantedBy=dev.ttyUSB0.device. You’ll need to disable and re-enable the service for the change to take effect.
# /etc/systemd/systemd/startfan.service
[Unit]
Description=blabla
After=dev.ttyUSB0.device

[Service]
Type=oneshot
ExecStart=/usr/bin/echo pwm_100 > /dev/ttyUSB0

[Install]
WantedBy=dev.ttyUSB0.device
  1. Use a timer with BootSec= to trigger the service. You can adjust the time. Disable the service and enable the timer for this one.
# /etc/systemd/systemd/startfan.service
[Unit]
Description=blabla
After=dev.ttyUSB0.device

[Service]
Type=oneshot
ExecStart=/usr/bin/echo pwm_100 > /dev/ttyUSB0
# /etc/systemd/systemd/startfan.timer
[Unit]
Description=blabla timer

[Timer]
OnBootSec=1min

[Install]
WantedBy=multi-user.target
  1. A udev rule might be better, it would be triggered by the device being detected.
1 Like

Awesome thankyou I will get started with this and see how it works out.

I’m not certain but I think ttyUSB0 on raspberry pi is the power usb-c port and isn’t used for any other data transfer. Would a udev attribute query confirm?

looking at device '/devices/platform/soc/fe980000.usb/usb3/3-1/3-1.4/3-1.4:1.>
    KERNEL=="ttyUSB0"
    SUBSYSTEM=="tty"
    DRIVER==""
    ATTR{power/control}=="auto"
    ATTR{power/runtime_active_time}=="0"
    ATTR{power/runtime_status}=="unsupported"
    ATTR{power/runtime_suspended_time}=="0"

  looking at parent device '/devices/platform/soc/fe980000.usb/usb3/3-1/3-1.4/3>
    KERNELS=="ttyUSB0"
    SUBSYSTEMS=="usb-serial"
    DRIVERS=="ch341-uart"
    ATTRS{port_number}=="0"
    ATTRS{power/control}=="auto"
    ATTRS{power/runtime_active_time}=="0"

Mar 02 22:49:51 pi4 systemd[332]: startfan.service: Failed to locate executable /usr/local/bin/startfan: Permission denied
Mar 02 22:49:51 pi4 systemd[332]: startfan.service: Failed at step EXEC spawning /usr/local/bin/startfan: Permission denied

.rw-r–r-- 47 root 2 Mar 21:59 startfan

.rw-r–r-- 170 root 2 Mar 22:42 startfan.service

I’m reluctant to add myself to the uucp group - isn’t this a security risk?

also on my build /usr/lib/systemd/system seems to be the proper dir for service files

Getting closer:

Mar 02 23:39:48 pi4 startfan[396]: /usr/local/bin/startfan: line 2: /dev/ttyUSB0: Permission denied

Do I need one more permission here?:

crw-rw----   188,0 root    2 Mar 23:42  ttyUSB0

Sorry it was late, went to bed. I’ll be out most of today, but I’ll try to check in again a few times.

ttyUSB0 is the first serial device detected, if what you’re using is always detected first then you’re good.

Whatever it is, it has a USB to serial chip.

/usr/local/startfan should have execute permission.

Not as far as I know.
https://wiki.archlinux.org/title/Arduino#Accessing_serial

That’s the place for service files installed by packages. /etc/systemd/system is the place for services installed by the admin, ie you.

The proper way to give yourself the permission is using the uucp group, this should work for an autostart script, it shouldn’t affect the systemd service unless it’s run as a user service.


I’ve just tested this and it works on my system, by works I mean the command seems to execute successfully when the service is run manually. I’m on a desktop and my user is part of the uucp group, not that either should matter in this case.

Mar 03 10:42:02 dm-pc systemd[1]: Starting blabla...
Mar 03 10:42:02 dm-pc echo[1341007]: pwm_100 > /dev/ttyUSB0
Mar 03 10:42:02 dm-pc systemd[1]: startfan.service: Deactivated successfully.
Mar 03 10:42:02 dm-pc systemd[1]: Finished blabla.
[Unit]
Description=blabla
After=dev.ttyUSB0.device

[Service]
Type=oneshot
ExecStart=/usr/bin/echo pwm_100 > /dev/ttyUSB0

[Install]
WantedBy=multi-user.target

There was a typo in my original post OneShot should be oneshot, but I guess you’ve already figured that out.

First of all I can’t thank you enough for trying to help. I have been successful at getting my service to run without errors using the above methods HOWEVER my fan doesn’t start when the system is powered off and back on which is the reason for the service in the first place. I can successfully run a command or script and start the fan and I have been successful in doing other (non-serial) tasks with this method AND I can get a service that calls a script to run without error but it just doesn’t do anything when the system powers back on. I am trying to start a fan on modified 3rd party hardware (a mini desktop type case) designed for raspberry pi. The original drivers are poorly coded or outdated and I have tested them on a few different OS’s and had to fix code on each one to get the fan working. I was sucessful on most other OS’s with the exception of Ubuntu 22 or higher. This is by far my favorite OS and I’m planning to build a home NAS with remote access from outside the network so I have a lot more work ahead but It’s all moot if I can’t have sufficient cooling. This is frustrating as this non-start issue has taken up a couple days now of my time.
I have gone with a more mickey mouse approach and created a home folder and user owned situation in which the script and service are owned by user and I am really close to making this work. The issue I have now is that my sudoers.d file is not sticking. I have added myself to the uucp group as you suggested. When I run:

systemctl --user status startfan.service

I get:

× startfan.service - cooling fan
     Loaded: loaded (/home/humble/.config/systemd/user/startfan.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Fri 2023-03-03 18:16:36 EST; 7s ago
   Duration: 2.158s
    Process: 4372 ExecStart=/home/humble/Documents/scripts/startfan.sh (code=exited, status=1/FAILURE)
   Main PID: 4372 (code=exited, status=1/FAILURE)
        CPU: 41ms

Mar 03 18:16:34 pi4 systemd[464]: Started cooling fan.
Mar 03 18:16:34 pi4 sudo[4377]: pam_systemd_home(sudo:auth): Not a user managed by systemd-homed: No home for user humble known
Mar 03 18:16:34 pi4 sudo[4377]: pam_unix(sudo:auth): conversation failed
Mar 03 18:16:34 pi4 startfan.sh[4377]: sudo: a terminal is required to read the password; either use the -S option to read from standard inpu>
Mar 03 18:16:34 pi4 sudo[4377]: pam_unix(sudo:auth): auth could not identify password for [humble]
Mar 03 18:16:36 pi4 startfan.sh[4377]: sudo: a password is required
Mar 03 18:16:36 pi4 systemd[464]: startfan.service: Main process exited, code=exited, status=1/FAILURE
Mar 03 18:16:36 pi4 systemd[464]: startfan.service: Failed with result 'exit-code'.

Here’s my script at ~/Documents/scripts/startfan.sh:

#!/bin/bash

serial_port='/dev/ttyUSB0'

sudo sh -c "echo pwm_100 > $serial_port"

this could probably be simpler but it works.
what’s strange is that if I open the file with something as simple as gnome-text-editor it prompts me for a password.

Screenshot from 2023-03-03 19-03-49

Here’s my service at ~/.config/systemd/user/startfan.service:

[Unit]
Description=cooling fan

[Service]
ExecStart=/home/humble/Documents/scripts/startfan.sh

[Install]
WantedBy=default.target

and finally I have a /etc/sudoers.d/startfan containing one line:

humble ALL=(ALL:ALL) NOPASSWD:/home/humble/Documents/scripts/startfan.sh

Yet you’ve only posted errors. I don’t reboot much so I can’t test it at boot. If you have a way of running the systemd service without errors then please post it. All we need to do is get it to run at boot.

I’m not so sure. Why are you using a user service and hacks to run something as root, when a system service will already run it as root.

My point with the service was that works (at least for me), and can be adapted to work at boot. We need to find the right way of running it.

The timer approach (option 3 from my first post) should work, have you tried it? You don’t really need the After= line, I should’ve taken that out.

EDIT:

You’re not trying to run startfan.sh with sudo, you’re using sh for some reason (it’s a symlink to bash, but can vary so it’s not portable, not that it matters much).

Allowing sh aka bash to be run as root without a password is definitely a security risk, and it won’t work via a script like that.

This is a better way of doing it echo pwm_100 | sudo tee /dev/ttyUSB0, and then you’d put tee in the sudoers file. Not that I’m suggesting you do it, this is the wrong approach, it’s just for information.

EDIT2:

I don’t know if you’ve already seen these, but if not then they may help.

https://wiki.archlinux.org/title/Systemd
https://wiki.archlinux.org/title/Systemd/Timers

1 Like

OK fan is off after reboot

○ startfan.service - cooling fan
     Loaded: loaded (/etc/systemd/system/startfan.service; enabled; preset: disabled)
     Active: inactive (dead) since Fri 2023-03-03 19:48:47 EST; 3s ago
   Duration: 85ms
TriggeredBy: ● startfan.timer
    Process: 1079 ExecStart=/usr/bin/startfan (code=exited, status=0/SUCCESS)
   Main PID: 1079 (code=exited, status=0/SUCCESS)
        CPU: 53ms

Mar 03 19:48:47 pi4 systemd[1]: Started cooling fan.
Mar 03 19:48:47 pi4 sudo[1080]:     root : PWD=/ ; USER=root ; COMMAND=/usr/bin/sh -c echo pwm_100 > /dev/ttyUSB0
Mar 03 19:48:47 pi4 sudo[1080]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Mar 03 19:48:47 pi4 sudo[1080]: pam_unix(sudo:session): session closed for user root
Mar 03 19:48:47 pi4 systemd[1]: startfan.service: Deactivated successfully.

I have timer and service in /etc/systemd/system

If i do not have a systemd in place the script turns the fan on.
If the systemd is in place the script does not turn on the fan

I have no sudoers in place atm
I have script named startfan (without the sh) in /usr/bin
I have system.servic and system.timer in etc/systemd/system
Every time i do status it says disabled - even when it has no errors
if the service is active the fan is off even when commands are passed to start it.

The files are root owned

Why add in the extra complication of a script and the call to sh?

The command you’re using calls sh aka bash as root to allow the bash redirection (>) to write to a root owned file. The service is already running as root, so it’s not needed.

Have you tried ExecStart=echo pwm_100 > /dev/ttyUSB0 yet? It may yield the same results or it may work.

Here’s one of my timer triggered services:

Loaded: loaded (/etc/systemd/system/switchoff.service; static)

Notice it doesn’t say enabled. The old service file may still be loaded.

sudo systemctl disable startfan
sudo systemctl daemon-reload
cat /etc/systemd/system/startfan.service

┬────────────────────────────────────────────────────────────────────────
│ File: /etc/systemd/system/startfan.service
───────┼────────────────────────────────────────────────────────────────────────
1 │ [Unit]
2 │ Description=cooling fan
3 │
4 │ [Service]
5 │ ExecStart=/usr/bin/startfan
6 │
7 │ [Install]
8 │ WantedBy=default.target

I will try editing to issue the command directly without script

Also remove the Install section, it’s not needed since it’s called by a timer. That’s why it says enabled disabled etc.

When you change the WantedBy line, you need to disable the service and re-enable it for the change to take effect. Except in this case you can’t re-enable it, which is fine that’s the way it should be.

When I remove the install line:

The unit files have no installation config (WantedBy=, RequiredBy=, Also=,
Alias= settings in the [Install] section, and DefaultInstance= for template
units). This means they are not meant to be enabled using systemctl.
 
Possible reasons for having this kind of units are:
• A unit may be statically enabled by being symlinked from another unit's
  .wants/ or .requires/ directory.
• A unit's purpose may be to act as a helper for some other unit which has
  a requirement dependency on it.
• A unit may be started when needed via activation (socket, path, timer,
  D-Bus, udev, scripted systemctl call, ...).
• In case of template units, the unit is meant to be enabled with some
  instance name specified.

That’s right it’s meant to be run by the timer. The timer needs to be enabled.

sudo systemctl enable startfan.timer

I’m trying to use the timer as I’m not sure how to guarantee it being run at the right time, without you playing around with things, taking up more of your time. So we use the timer to run it some time after boot when we know the device is ready.

You may need to tweak the time.

OK no fan on reboot

○ startfan.service - cooling fan
     Loaded: loaded (/etc/systemd/system/startfan.service; static)
     Active: inactive (dead) since Fri 2023-03-03 20:22:19 EST; 3s ago
   Duration: 6ms
TriggeredBy: ● startfan.timer
    Process: 1088 ExecStart=echo pwm_100 > /dev/ttyUSB0 (code=exited, status=0/SUCCESS)
   Main PID: 1088 (code=exited, status=0/SUCCESS)
        CPU: 7ms

Mar 03 20:22:19 pi4 systemd[1]: Started cooling fan.
Mar 03 20:22:19 pi4 echo[1088]: pwm_100 > /dev/ttyUSB0
Mar 03 20:22:19 pi4 systemd[1]: startfan.service: Deactivated successfully.

all other services in this dir have
lrwxrwxrwx
mine have
.rw-r–r–

the “l” on other service permissions is because they are simlinked to /usr/lib/… i think

a simple

echo pwm_100 > /dev/ttyUSB0

in terminal -without sudo -works - IF there’s no systemd service