Compare commits
10 Commits
16db9c6309
...
2aa0ae2bcd
Author | SHA1 | Date |
---|---|---|
ABelliqueux | 2aa0ae2bcd | |
ABelliqueux | 303d55dc85 | |
ABelliqueux | 6a049ff665 | |
ABelliqueux | 758c68a80d | |
ABelliqueux | d6148d00e5 | |
ABelliqueux | f59a38e506 | |
ABelliqueux | 3feeca4e6d | |
ABelliqueux | d9d141678f | |
ABelliqueux | f4a43d745c | |
ABelliqueux | 01e10dbaee |
Binary file not shown.
|
@ -8,14 +8,31 @@ from math import floor
|
|||
from os import environ
|
||||
import signal
|
||||
import sys
|
||||
from time import sleep
|
||||
from time import sleep, time
|
||||
# Relay
|
||||
import RPi.GPIO as GPIO
|
||||
# OLED SSD1306
|
||||
from luma.core.interface.serial import i2c
|
||||
from luma.core.render import canvas
|
||||
from luma.oled.device import ssd1306
|
||||
from PIL import Image, ImageDraw
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
# Pot_cap
|
||||
import pigpio
|
||||
import pot_cap
|
||||
min_val = 8
|
||||
max_val = 298
|
||||
vol_mult = 100/(max_val-min_val)
|
||||
volume = 0
|
||||
v_1 = 0
|
||||
v_2 = 0
|
||||
ctrlc_pressed = False
|
||||
pot_cap_gpio = 23
|
||||
drain_ms = 0.8
|
||||
timeout_s = 1.0
|
||||
|
||||
|
||||
jfont = ImageFont.truetype('DejaVuSansMono.ttf', 10)
|
||||
|
||||
# MPD config
|
||||
off_delay = 3
|
||||
|
@ -40,6 +57,8 @@ for BTN in BTNS:
|
|||
GPIO.setup(BTNS[BTN]['GPIO'], GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||
|
||||
# SSD1306 setup - bouding box is (0, 0, 127, 63), 128x64
|
||||
# TODO : Set an idle_display timer and run device.hide()/device.show() according to value
|
||||
# GPIOS 2, 3
|
||||
serial = i2c(port=1, address=0x3C)
|
||||
device = ssd1306(serial)
|
||||
|
||||
|
@ -50,10 +69,10 @@ btn_height = 10
|
|||
menu_line_width = 1
|
||||
menu_bar_y = device.height - btn_height - menu_line_width - 1
|
||||
ui_text_x = 4
|
||||
ui_vol_width = 6
|
||||
ui_vol_y = 4
|
||||
ui_vol_x = device.width - ui_vol_width - 8
|
||||
ui_vol_icon_coords = (ui_vol_x - 10, 4)
|
||||
ui_vol_width = 18
|
||||
ui_vol_y = menu_bar_y - 14
|
||||
ui_vol_x = device.width - ui_vol_width
|
||||
ui_vol_icon_coords = (ui_vol_x - 10, ui_vol_y+2)
|
||||
ui_vol_icon_polygon = [0,3,3,3,8,0,8,8,3,5,0,5]
|
||||
play_icon = [0,0,8,4,0,8]
|
||||
# ~ play_icon_ = [0,0,8,4,0,8]
|
||||
|
@ -189,24 +208,24 @@ def update_display(device, currentsong:dict, status:dict, mode:str, cursor_pos:i
|
|||
# Draw dynamic UI
|
||||
ui = static_ui.copy()
|
||||
draw = ImageDraw.Draw(ui)
|
||||
draw.text((ui_vol_x, ui_vol_y), status['volume'], fill="white")
|
||||
if mode == 'playback':
|
||||
if len(currentsong):
|
||||
draw.text((ui_text_x, 2), currentsong['artist'], fill="white")
|
||||
draw.text((ui_text_x, 14), currentsong['title'], fill="white")
|
||||
draw.text((ui_text_x, 26), currentsong['album'], fill="white")
|
||||
draw.text((ui_text_x, 2), currentsong['artist'], fill="white", font=jfont)
|
||||
draw.text((ui_text_x, 14), currentsong['title'], fill="white", font=jfont)
|
||||
draw.text((ui_text_x, 26), currentsong['album'], fill="white", font=jfont)
|
||||
if 'elapsed' in status:
|
||||
draw.text((ui_text_x, 38), "{}/{}".format(sectomin(status['elapsed']), sectomin(status['duration'])), fill="white")
|
||||
draw.text((ui_text_x, 38), "{}/{}".format(sectomin(status['elapsed']), sectomin(status['duration'])), fill="white", font=jfont)
|
||||
elif mode == 'browse':
|
||||
draw.regular_polygon(bounding_circle=(ui_text_x + 2, 6, 4), n_sides=3, rotation=270, outline="white", fill="black")
|
||||
if (type(ui_state['current_selection']) is list) and (len(ui_state['current_selection'])):
|
||||
draw.text((ui_text_x + 10, 1), ui_state['current_selection'][cursor_pos], fill="white")
|
||||
draw.text((ui_text_x + 10, 1), ui_state['current_selection'][cursor_pos], fill="white", font=jfont)
|
||||
if (len(ui_state['current_selection']) > 1) and (cursor_pos < len(ui_state['current_selection'])-1):
|
||||
draw.text((ui_text_x, 14), ui_state['current_selection'][cursor_pos+1], fill="white")
|
||||
draw.text((ui_text_x, 14), ui_state['current_selection'][cursor_pos+1], fill="white", font=jfont)
|
||||
if len(ui_state['current_selection']) > 2 and (cursor_pos < len(ui_state['current_selection'])-2):
|
||||
draw.text((ui_text_x, 26), ui_state['current_selection'][cursor_pos+2], fill="white")
|
||||
draw.text((ui_text_x, 26), ui_state['current_selection'][cursor_pos+2], fill="white", font=jfont)
|
||||
else:
|
||||
draw.text((ui_text_x + 10, 1), ui_state['current_selection'], fill="white")
|
||||
draw.text((ui_text_x + 10, 1), ui_state['current_selection'], fill="white", font=jfont)
|
||||
draw.text((ui_vol_x, ui_vol_y), "{:02d}".format(int(status['volume'])), fill="white", font=jfont)
|
||||
device.contrast(0)
|
||||
device.display(ui)
|
||||
|
||||
|
@ -257,10 +276,15 @@ def send_mpd_cmd(client, cmd:str, ui_state:dict):
|
|||
if client.status()['state'] != 'stop':
|
||||
client.next()
|
||||
elif cmd == 'toggle':
|
||||
# ~ global MODES
|
||||
if client.status()['state'] in idle_states:
|
||||
client.play()
|
||||
MODES['playback']['BTN_3']['ICON'] = apply_xy_offset(play_icon, MODES['playback']['BTN_3']['XY'])
|
||||
static_ui = generate_static_ui('playback')
|
||||
else:
|
||||
client.pause()
|
||||
MODES['playback']['BTN_3']['ICON'] = apply_xy_offset(pause_icon, MODES['playback']['BTN_3']['XY'])
|
||||
static_ui = generate_static_ui('playback')
|
||||
elif cmd == 'stop':
|
||||
client.stop()
|
||||
elif cmd == 'down':
|
||||
|
@ -327,6 +351,15 @@ def send_mpd_cmd(client, cmd:str, ui_state:dict):
|
|||
|
||||
|
||||
def main(args):
|
||||
# Idle timer
|
||||
ui_idle_for = 0
|
||||
# Pot_cap
|
||||
# Connect to Pi.
|
||||
pi = pigpio.pi()
|
||||
# Instantiate Pot/Cap reader.
|
||||
pc = pot_cap.reader(pi, pot_cap_gpio, drain_ms, timeout_s)
|
||||
start = time()
|
||||
|
||||
previous_song_id = None
|
||||
previous_state = None
|
||||
paused_since_seconds = 0
|
||||
|
@ -360,11 +393,29 @@ def main(args):
|
|||
global static_ui
|
||||
static_ui = generate_static_ui(current_mode)
|
||||
while ctrlc_pressed is False:
|
||||
# pot_cap
|
||||
global v_1
|
||||
global v_2
|
||||
global volume
|
||||
s, v, r = pc.read()
|
||||
if s and r < 4:
|
||||
volume = round(v*vol_mult)
|
||||
if (abs(volume - v_1) > 1) and (abs(volume - v_2) > 2):
|
||||
print("Volume: {}".format(volume))
|
||||
if volume < min_val:
|
||||
volume = 0
|
||||
if volume > 100:
|
||||
volume = 100
|
||||
client.setvol(100-volume)
|
||||
ui_idle_for = 0
|
||||
v_2 = v_1
|
||||
v_1 = volume
|
||||
# MPD
|
||||
mpd_status = client.status()
|
||||
if len(mpd_status):
|
||||
mpd_client_status = mpd_status
|
||||
mpd_client_currentsong = client.currentsong()
|
||||
#print(mpd_client_status['volume'])
|
||||
if 'state' in mpd_client_status:
|
||||
play_state = mpd_client_status['state']
|
||||
if 'songid' in mpd_client_status:
|
||||
|
@ -399,12 +450,26 @@ def main(args):
|
|||
if (GPIO.input(BTNS[BTN]['GPIO']) == 0) and (GPIO.input(BTNS[BTN]['GPIO']) != BTNS[BTN]['state']):
|
||||
ui_state = send_mpd_cmd(client, MODES[current_mode][BTN]['FUNCTION'], ui_state)
|
||||
print("{} pressed".format(MODES[current_mode][BTN]['FUNCTION']))
|
||||
# Reset idle timer
|
||||
ui_idle_for = 0
|
||||
# Save previous state
|
||||
BTNS[BTN]['state'] = GPIO.input(BTNS[BTN]['GPIO'])
|
||||
if (GPIO.input(BTNS[BTN]['GPIO']) == 1) and (GPIO.input(BTNS[BTN]['GPIO']) != BTNS[BTN]['state']):
|
||||
# Save previous state
|
||||
BTNS[BTN]['state'] = GPIO.input(BTNS[BTN]['GPIO'])
|
||||
update_display(device, mpd_client_currentsong, mpd_client_status, current_mode, ui_state['cursor_pos'])
|
||||
if int(ui_idle_for) < 10:
|
||||
ui_idle_for += .2
|
||||
device.show()
|
||||
update_display(device, mpd_client_currentsong, mpd_client_status, current_mode, ui_state['cursor_pos'])
|
||||
elif int(ui_idle_for) == 10:
|
||||
print("Ui idle for 10 seconds, suspending display...")
|
||||
# Avoid further execution
|
||||
ui_idle_for = 11
|
||||
device.hide()
|
||||
# pot_cap
|
||||
pc.cancel() # Cancel the reader.
|
||||
pi.stop() # Disconnect from Pi.
|
||||
|
||||
device.cleanup()
|
||||
client.disconnect()
|
||||
return 0
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
[Unit]
|
||||
Description=Mpd listen python script
|
||||
After=network.target
|
||||
After=mpd.service
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/home/music/mpdlisten
|
||||
ExecStart=/home/music/mpdlisten/mpdlisten.py
|
||||
WorkingDirectory=/home/%u/mpdlisten
|
||||
ExecStart=/home/%u/mpdlisten/mpdlisten.py
|
||||
KillSignal=SIGINT
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
WantedBy=default.target
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# pot_cap.py
|
||||
# 2016-09-26
|
||||
# Public Domain
|
||||
|
||||
import time
|
||||
import pigpio
|
||||
|
||||
class reader:
|
||||
"""
|
||||
A class to measure the time taken to charge a capacitor
|
||||
through a resistance. The time taken will be propotional
|
||||
to the voltage, resistance, and capacitance. If two values
|
||||
are fixed the third can be estimated.
|
||||
|
||||
The following circuit should be used.
|
||||
|
||||
3V3 ----- Resistor --+-- Capacitor ----- Ground
|
||||
|
|
||||
+-- GPIO
|
||||
|
||||
"""
|
||||
def __init__(self, pi, gpio, drain_ms=1.0, timeout_s=1.0):
|
||||
"""
|
||||
Instantiate with the Pi and GPIO of the resistor/capacitor
|
||||
system to monitor.
|
||||
|
||||
Optionally the time taken to fully drain the capacitor
|
||||
may be give as drain_ms. The value defaults to
|
||||
1 millisecond.
|
||||
|
||||
Optionally a timeout may be specified as timeout_s. The
|
||||
value defaults to 1.0 seconds.
|
||||
|
||||
If the readings appear to vary too much in static
|
||||
conditions or there are many False results with massive
|
||||
readings perhaps the capacitor isn't fully discharging.
|
||||
Try increasing draim_ms.
|
||||
|
||||
If False is always returned perhaps the capacitor needs
|
||||
more time to charge. Try increasing timeout_s.
|
||||
"""
|
||||
|
||||
self.pi = pi
|
||||
self.gpio = gpio
|
||||
self.drain_ms = drain_ms
|
||||
self.timeout_s = timeout_s
|
||||
self._timeout_us = timeout_s * 1000000.0
|
||||
|
||||
"""
|
||||
Use a script on the daemon to do the time critical bit.
|
||||
|
||||
It saves the tick in v0, changes the mode of p0 to an input,
|
||||
gets the tick and subtracts the first tick, divides by 2 to
|
||||
get the range, adds the range to the first tick to get the
|
||||
estimated start tick. Returns the estimated start tick in p2
|
||||
and range in p3. Finally p1 is incremented to indicate the
|
||||
script has completed.
|
||||
"""
|
||||
|
||||
self._sid = pi.store_script(
|
||||
b't sta v0 m p0 r t sub v0 div 2 sta p3 add v0 sta p2 inr p1 ')
|
||||
|
||||
s = pigpio.PI_SCRIPT_INITING
|
||||
|
||||
while s == pigpio.PI_SCRIPT_INITING:
|
||||
s, p = self.pi.script_status(self._sid)
|
||||
time.sleep(0.001)
|
||||
|
||||
self._cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._cbf)
|
||||
|
||||
def _cbf(self, g, l, t):
|
||||
"""
|
||||
Record the tick when the GPIO becomes high.
|
||||
"""
|
||||
if l == 1:
|
||||
self._end = t
|
||||
|
||||
def read(self):
|
||||
"""
|
||||
Triggers and returns a reading.
|
||||
|
||||
A tuple of the reading status (True for a good reading,
|
||||
False for a timeout or outlier), the reading, and the
|
||||
range are returned.
|
||||
|
||||
The reading is the number of microseconds taken for the
|
||||
capacitor to charge. The range is a measure of how
|
||||
accurately the start of recharge was measured as +/-
|
||||
microseconds.
|
||||
"""
|
||||
|
||||
timeout = time.time() + self.timeout_s
|
||||
|
||||
self.pi.write(self.gpio, 0)
|
||||
|
||||
time.sleep(self.drain_ms/1000.0)
|
||||
|
||||
while (self.pi.read(self.gpio) != 0) and (time.time() < timeout):
|
||||
time.sleep(0.001)
|
||||
|
||||
self._end = None
|
||||
|
||||
self.pi.run_script(self._sid, [self.gpio, 0])
|
||||
|
||||
while time.time() < timeout:
|
||||
s, p = self.pi.script_status(self._sid)
|
||||
if p[1]:
|
||||
break
|
||||
time.sleep(0.001)
|
||||
|
||||
# p[2] is start charge tick from script
|
||||
# p[3] is +/- range from script
|
||||
|
||||
if time.time() < timeout:
|
||||
|
||||
_start = p[2]
|
||||
if _start < 0:
|
||||
_start += (1<<32)
|
||||
|
||||
while self._end is None and time.time() < timeout:
|
||||
time.sleep(0.001)
|
||||
|
||||
if self._end is not None:
|
||||
diff = pigpio.tickDiff(_start, self._end)
|
||||
# Discard obvious outliers
|
||||
if (diff < self._timeout_us) and (p[3] < 6):
|
||||
return True, diff, p[3]
|
||||
else:
|
||||
return False, diff, p[3]
|
||||
|
||||
return False, 0, 0
|
||||
|
||||
def cancel(self):
|
||||
"""
|
||||
Cancels the reader and releases resources.
|
||||
"""
|
||||
self.pi.delete_script(self._sid)
|
||||
self._cb.cancel()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import sys
|
||||
import time
|
||||
import pigpio
|
||||
import pot_cap
|
||||
|
||||
RUN_TIME = 30
|
||||
POT_CAP_GPIO = 23
|
||||
DRAIN_MS = 1.0
|
||||
TIMEOUT_S = 1.0
|
||||
|
||||
# ./pot_cap.py [run time [gpio [drain ms [timeout s]]]]
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
run_time = float(sys.argv[1])
|
||||
else:
|
||||
run_time = RUN_TIME
|
||||
|
||||
if len(sys.argv) > 2:
|
||||
pot_cap_gpio = int(sys.argv[2])
|
||||
else:
|
||||
pot_cap_gpio = POT_CAP_GPIO
|
||||
|
||||
if len(sys.argv) > 3:
|
||||
drain_ms = float(sys.argv[3])
|
||||
else:
|
||||
drain_ms = DRAIN_MS
|
||||
|
||||
if len(sys.argv) > 4:
|
||||
timeout_s = float(sys.argv[4])
|
||||
else:
|
||||
timeout_s = TIMEOUT_S
|
||||
|
||||
pi = pigpio.pi() # Connect to Pi.
|
||||
|
||||
print("# rt={:.1f} g={} drain={:.1f} timeout={:.1f}".format(
|
||||
run_time, pot_cap_gpio, drain_ms, timeout_s))
|
||||
|
||||
# Instantiate Pot/Cap reader.
|
||||
pc = pot_cap.reader(pi, pot_cap_gpio, drain_ms, timeout_s)
|
||||
|
||||
start = time.time()
|
||||
|
||||
while (time.time()-start) < run_time:
|
||||
|
||||
s, v, r = pc.read()
|
||||
if s and r < 4:
|
||||
print("{} {} {}".format(s, v, r))
|
||||
time.sleep(0.01)
|
||||
|
||||
pc.cancel() # Cancel the reader.
|
||||
pi.stop() # Disconnect from Pi.
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
# mpdlistenpy
|
||||
|
||||
This python script is supposed to run on a rpi and does the following :
|
||||
|
||||
* Relay trigger : Watches a MPD instance for play/pause/stop states and activates a relay via GPIOs accordingly ; the usecase for this is powering on/off a pair of speakers only when something is running.
|
||||
* OLED display : Drives a 0.96" OLED display (ssd1306) to display MPD status (volume, current artist, album, title...)
|
||||
* Button input : watches GPIOs for button input ; I'm using 5 push buttons for controlling playback (previous, next, toggle playback, stop, menu) or browse the database and add stuff to the playlist.
|
||||
* Potentiometer input : Watches a GPIO for estimating the resistance of a rotary potentiometer and set volume accordingly.
|
||||
|
||||
## Setup
|
||||
|
||||
### Software
|
||||
|
||||
1. Install the latest **light** version of Raspberry Pi OS and run it on the RPI model of your choice.
|
||||
2. Install the following dependencies (these are for mpd, the python script and filesystem handling):
|
||||
```
|
||||
sudo apt install --no-install-recommends --no-install-suggests mpd gvfs-fuse gvfs-backends gvfs libglib2.0-bin python3-musicpd python3-luma.oled i2c-tools python3-pil libjpeg-dev zlib1g-dev libfreetype6-dev liblcms2-dev libopenjp2-7 libtiff5-dev exfat-fuse
|
||||
```
|
||||
3. Configure '~/.config/mpd/mpd.conf' as you please and enable mpd systemd unit :
|
||||
```
|
||||
systemctl --user --full enable mpd
|
||||
```
|
||||
4. See [Installing the systemd service](#installing-the-systemd-service) for installing the mpdlistenpy systemd service and start/enable it.
|
||||
5. See [Automounting Samba shares on startup](#automounting-samba-shares-on-startup) for setting up an automount service and start/enable it.
|
||||
|
||||
### Hardware
|
||||
|
||||
#### Overall GPIOs usage
|
||||
|
||||
| FUNCTION | GPIO # |
|
||||
| --- | --- |
|
||||
| OLED | GND, 3.3V, 2(SDA), 3(SCL) |
|
||||
| 5 BUTTONS | GND, 7, 8, 9, 11, 25 |
|
||||
| POTENTIOMETER | GND, 3.3V, 23 |
|
||||
| RELAY | GND, 5V, 17 |
|
||||
|
||||
You can check these here : [https://pinout.xyz/](https://pinout.xyz/)
|
||||
|
||||
#### Oled screen
|
||||
|
||||
Using the SSD1306 OLED screen involves a few steps described here :
|
||||
|
||||
[https://luma-oled.readthedocs.io/en/latest/hardware.html](https://luma-oled.readthedocs.io/en/latest/hardware.html)
|
||||
|
||||
and here :
|
||||
|
||||
[https://luma-oled.readthedocs.io/en/latest/software.html](https://luma-oled.readthedocs.io/en/latest/software.html)
|
||||
|
||||
Once you've gone through these steps, you should be good to go.
|
||||
|
||||
#### Relay circuit
|
||||
|
||||
We're using the circuit described on projects-raspberry.com :
|
||||
|
||||
##### Components
|
||||
|
||||
* 5V DC coil relay
|
||||
* BC337 NPN transistor
|
||||
* 1N4002 [diode](https://en.wikipedia.org/wiki/1N400x_general-purpose_diodes)
|
||||
* 1KΩ resistor
|
||||
|
||||
##### Diagram
|
||||
|
||||
![https://web.archive.org/web/20240217011938/https://projects-raspberry.com/raspberry-pi-driving-a-relay-using-gpio/](https://web.archive.org/web/20240217011938im_/https://projects-raspberry.com/wp-content/uploads/2015/04/Raspberry-Pi-%E2%80%93-Driving-a-Relay-using-GPIO2.jpg)
|
||||
|
||||
*source: [https://projects-raspberry.com/raspberry-pi-driving-a-relay-using-gpio/](https://web.archive.org/web/20240217011938/https://projects-raspberry.com/raspberry-pi-driving-a-relay-using-gpio/)*
|
||||
|
||||
#### Buttons circuit
|
||||
|
||||
Dead simple way described here, using a common GND, and 1 GPIO/button :
|
||||
|
||||
[http://razzpisampler.oreilly.com/ch07.html](https://web.archive.org/web/20240121074741/http://razzpisampler.oreilly.com/ch07.html)
|
||||
|
||||
The only difference is the addition of a resistor on the GND rail.
|
||||
|
||||
If you're short on GPIOs, there is a way to use a single GPIO for multiple buttons based on resistance described here :
|
||||
|
||||
[https://www.instructables.com/RaspberryPi-Multiple-Buttons-On-One-Digital-Pin/](https://www.instructables.com/RaspberryPi-Multiple-Buttons-On-One-Digital-Pin/)
|
||||
|
||||
#### Potentiometer circuit
|
||||
|
||||
Using the 'step response' method described [here](http://razzpisampler.oreilly.com/ch08.html#Discussion) (It's the same principle as in the link above),
|
||||
we can use an analog potentiometer to control volume.
|
||||
|
||||
The solution described in the previous link is not very accurate though, so we'll be using an alternative solution offered by abyz.me.uk :
|
||||
|
||||
[https://abyz.me.uk/rpi/pigpio/examples.html#Python_pot_cap_py](https://abyz.me.uk/rpi/pigpio/examples.html#Python_pot_cap_py)
|
||||
|
||||
##### Components
|
||||
|
||||
* 100nf Ceramic capacitor
|
||||
* 5KΩ Potentiometer
|
||||
|
||||
##### Diagram
|
||||
|
||||
```
|
||||
3V3 ----- Potentiometer --+-- Capacitor ----- Ground
|
||||
|
|
||||
+-- GPIO 23
|
||||
```
|
||||
|
||||
Instructions for use are in the source file. The library ('pot_cap.py') is included in this project for convenience.
|
||||
|
||||
You might have to install the 'pigpio' library though :
|
||||
|
||||
```
|
||||
sudo apt install python3-pigpio
|
||||
```
|
||||
|
||||
You can find out more about installing 'pigpio' here :
|
||||
|
||||
[https://abyz.me.uk/rpi/pigpio/download.html](https://abyz.me.uk/rpi/pigpio/download.html)
|
||||
|
||||
## Optional steps
|
||||
|
||||
### Installing the systemd service
|
||||
|
||||
* Copy the provided service file 'mpdlistenpy.service' to '~/.config/systemd/user/mpdlistenpy.service'.
|
||||
* Update, enable and start the service as a user :
|
||||
|
||||
```
|
||||
# If you need to edit the path to the script (should be in ~/mpdlisten by default)
|
||||
# systemctl --user --full edit mpdlistenpy.service
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable mpdlistenpy.service
|
||||
systemctl --user start mpdlistenpy.service
|
||||
```
|
||||
|
||||
### Automounting Samba shares on startup
|
||||
|
||||
If you want to setup a systemd service that mounts smb shares on startup, follow these instructions :
|
||||
|
||||
[Automount SMB shares on startup](https://forge.chapril.org/ABelliqueux/smbautomount)
|
||||
|
||||
*source :* [https://root.nix.dk/en/utility-scripts/mount-samba-share-as-user](https://root.nix.dk/en/utility-scripts/mount-samba-share-as-user)
|
||||
|
||||
### Automounting USB
|
||||
|
||||
[https://gist.github.com/zebrajaeger/168341df88abb6caaea5a029a2117925](https://gist.github.com/zebrajaeger/168341df88abb6caaea5a029a2117925)
|
Loading…
Reference in New Issue