Skip to content

Commit

Permalink
Merge pull request #1159 from MiczFlor/develop
Browse files Browse the repository at this point in the history
Release 2.2
  • Loading branch information
s-martin authored Nov 23, 2020
2 parents 70f989b + e6f5676 commit 9dc8d0d
Show file tree
Hide file tree
Showing 33 changed files with 977 additions and 473 deletions.
1 change: 1 addition & 0 deletions .github/workflows/dockerimage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ jobs:
docker build . --file ./ci/Dockerfile.buster.test_install.amd64 --tag rpi-jukebox-rfid-buster:latest
docker run --rm -i rpi-jukebox-rfid-buster:latest /code/scripts/installscripts/tests/run_installation_tests.sh
docker run --rm -i rpi-jukebox-rfid-buster:latest /code/scripts/installscripts/tests/run_installation_tests2.sh
docker run --rm -i rpi-jukebox-rfid-buster:latest /code/scripts/installscripts/tests/run_installation_tests3.sh
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ scripts/gpio-buttons.py

shared/*
playlists/*
pythonenv*/*
logs/*

# Byte-compiled / optimized / DLL files
Expand Down
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,32 @@ A contactless jukebox for the Raspberry Pi, playing audio files, playlists, podc

* **Gitter Community** we got ourselves a gitter community; chat us up at https://gitter.im/phoniebox

* **Phoniebox [2.1.1](https://github.com/MiczFlor/RPi-Jukebox-RFID/milestone/5?closed=1) released (2020-10-14)**
* **Phoniebox [2.2](https://github.com/MiczFlor/RPi-Jukebox-RFID/milestone/4?closed=1) released (2020-xx-xx)**

The [2.1](https://github.com/MiczFlor/RPi-Jukebox-RFID/milestone/3?closed=1) release was pushed through the doors with many contributors (some of which in alphabetical order): @andreasbrett @BerniPi @juhrmann @Luegengladiator @MarkusProchaska @MarlonKrug @patrickweigelt @princemaxwell @RalfAlbers @s-martin @themorlan @veloxidSchweiz @xn--nding-jua. [List of all contributors](https://github.com/MiczFlor/RPi-Jukebox-RFID/graphs/contributors)
The [2.2](https://github.com/MiczFlor/RPi-Jukebox-RFID/milestone/4?closed=1) release was pushed through the doors with many contributors (some of which in alphabetical order): @andreasbrett @BerniPi @juhrmann @Luegengladiator @MarkusProchaska @MarlonKrug @patrickweigelt @princemaxwell @RalfAlbers @s-martin @themorlan @veloxidSchweiz @xn--nding-jua. [List of all contributors](https://github.com/MiczFlor/RPi-Jukebox-RFID/graphs/contributors)

## What's new in version 2.1.1?
## What's new in version 2.2?

* Use [multiple readers](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/1012#issue-434052529) simultaneously
* Improved [GPIO control](components/gpio_control/README.md) and integrated in **one-line install script**
* Integrated selection of RFID readers in **one-line install script**
* Improved handling of playlists in web UI
* Improved Spotify handling of albums covers, etc.
* Seeking via GPIO buttons
* :fire: **Fixed location of gpio_settings.ini** for [GPIO control](components/gpio_control/README.md)
* Added support for files with embedded chapters metada (like m4a) enhancement
* Added customizable poweroff command bash enhancement
* Finally fixed resume function...
* Lots of fixed bugs and minor improvements...
* Status LED, Rotary Button, Volume Up/Down, custom music directory for +Spotify, Startup sound volume

**What's still hot?**

* The constantly improved **one-line install script** handles both **Classic** and **+Spotify** when [setting up your Phoniebox](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/INSTALL-stretch#one-line-install-command)
* integrated improved [GPIO control](components/gpio_control/README.md)
* integrated selection of RFID readers and uses [multiple readers](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/1012#issue-434052529) simultaneously
* features *non-interactive* installs based on a config file
* **[WiFi management](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/MANUAL#wifi-settings)**
* RFID cards to **toggle Wifi** (or switch it on/off)
* Read out the Wifi IP address (if you are connecting to a new network and don't know where to point your browser)
* **Hotspot** Phoniebox: [ad-hoc hotspot](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/967) if no known network found (IP: 10.0.0.5 SSID: phoniebox Password: PlayItLoud)
* **Touchscreen** LCD display Player (file: `index-lcd.php`in web app)
* Improved **one-line install script** featuring *non-interactive* installs based on a config file
* Integrate your [Phoniebox in your Smart Home](https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/581).
* Integrate your [Phoniebox in your Smart Home](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Smart-Home-remote-control-with-MQTT).
* Smoother [Web App running on ajax](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/623).
* New [search form for local files](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/710)
* The **one-line install script** handles both: **Classic** and **+Spotify** when [setting up your Phoniebox](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/INSTALL-stretch#one-line-install-command).
* Control the debug logs in the web app (individual scripts switched on/off, empty log file).
* Set [maximum volume with RFID](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/633) cards.
* Control via [**wifi web app**](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/MANUAL#webapp) from your phone, tablet or PC. You can play, upload, move files, assign new RFID cards, control playout, settings, etc.
Expand Down Expand Up @@ -233,6 +233,7 @@ Here is a list of equipment needed. You can find a lot second hand online (save

### Arcade Buttons

* [USB Interface for Arcade buttons](https://amzn.to/3nRAtIS) if you insist on not soldering hardware. (23rd Nov 2020: GPIO control script not yet part of the repo)
* Arcade Buttons / Sensors (one of these might suit you)
* [Arcade Buttons / Schalter in various colours](https://amzn.to/2QMxe9r) if you want buttons for the GPIO control.
* [Arcade Buttons wit LED and custom icons](https://amzn.to/2MWQ6hq) as used by [@splitti](https://splittscheid.de/selfmade-phoniebox/#3C).
Expand Down
3 changes: 2 additions & 1 deletion ci/Dockerfile.buster.test_install.amd64
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ RUN groupadd --gid 1000 pi ;\
chown -R 1000:1000 /code /home/pi ;\
chmod +x /code/scripts/installscripts/buster-install-default.sh ;\
chmod +x /code/scripts/installscripts/tests/run_installation_tests.sh ;\
chmod +x /code/scripts/installscripts/tests/run_installation_tests2.sh
chmod +x /code/scripts/installscripts/tests/run_installation_tests2.sh ;\
chmod +x /code/scripts/installscripts/tests/run_installation_tests3.sh

RUN export DEBIAN_FRONTEND=noninteractive ;\
apt-get update ;\
Expand Down
4 changes: 2 additions & 2 deletions components/displays/HD44780-i2c/i2c_lcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def sec_to_min_and_sec(seconds):
# #
## read in track number #
try: #
track_number = current_song_infos['track'] #
track_number = str(int(status['song'])+1) #
except KeyError: #
track_number = "1" #
## read in playlistlength #
Expand Down Expand Up @@ -406,7 +406,7 @@ def sec_to_min_and_sec(seconds):
if i_counter >= 65000: #
i_counter = 1000 # <-- not 0, cause the display could be off #
######################################################################################

####################### REMIND STUFF FOR NEXT CYCLE #################################
last_state = state #
last_title = title #
Expand Down
5 changes: 5 additions & 0 deletions components/gpio_control/GPIODevices/simple_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ def __init__(self, pin, action=lambda *args: None, name=None, bouncetime=500, ed
bouncetime=self.bouncetime)

def callbackFunctionHandler(self, *args):
if (len(args) > 0 and args[0] == self.pin):
logger.debug('args before: {}'.format(args))
args = args[1:]
logger.debug('args after: {}'.format(args))

if self.hold_repeat:
return self.holdAndRepeatHandler(*args)
logger.info('{}: executre callback'.format(self.name))
Expand Down
8 changes: 5 additions & 3 deletions components/gpio_control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@ It uses to a configuration file to configure the active devices.

## How to edit configuration files?
The configuration file is located here: `~/RPi-Jukebox-RFID/settings/gpio_settings.ini`
Editing the configuration file and restarting the service will activate the new settings.
Editing the configuration file and restarting the service with `sudo systemctl restart phoniebox-gpio-control` will activate the new settings.

In the following the different devices are described.
Each device can have actions which correspond to function calls.
Up to now the following input devices are implemented:
* **Button**:
A simple button which has a hold and repeat functionality as well as a delayed action.
It can be configured using the keywords: Pin, hold_time, functionCall
It can be configured using the keywords: Pin (**use GPIO number here**), hold_time, functionCall

* **RotaryEncoder**:
Control of a rotary encoder, for example KY040, see also in
[Wiki](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Audio-RotaryKnobVolume)
it can be configured using pinA, pinB, functionCallIncr, functionCallDecr, timeBase=0.1
it can be configured using pinA (**use GPIO number here**), pinB (**use GPIO number here**), functionCallIncr, functionCallDecr, timeBase=0.1

* **TwoButtonControl**:
This Device uses two Buttons and implements a third action if both buttons are pressed together.

Many example files are located in `~/RPi-Jukebox-RFID/components/gpio_control/example_configs/`.
2 changes: 1 addition & 1 deletion components/gpio_control/function_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def functionCallPlayerStop(*args):
function_call("{command} -c=playerstop".format(command=playout_control),
shell=True)


def functionCallPlayerSeekFwd(*args):
function_call("{command} -c=playerseek -v=+10".format(command=playout_control), shell=True)

Expand All @@ -77,7 +78,6 @@ def functionCallPlayerSeekBack(*args):
function_call("{command} -c=playerseek -v=-10".format(command=playout_control), shell=True)



def getFunctionCall(functionName):
logger.error('Get FunctionCall: {} {}'.format(functionName, functionName in locals()))
getattr(sys.modules[__name__], str)
Expand Down
2 changes: 1 addition & 1 deletion components/gpio_control/gpio_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def get_all_devices(config):
logger.setLevel('INFO')

config = configparser.ConfigParser(inline_comment_prefixes=";")
config_path = os.path.expanduser('~/.config/phoniebox/gpio_settings.ini')
config_path = os.path.expanduser('/home/pi/RPi-Jukebox-RFID/settings/gpio_settings.ini')
config.read(config_path)

devices = get_all_devices(config)
Expand Down
4 changes: 2 additions & 2 deletions components/gpio_control/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ if [[ $(id -u) != 0 ]]; then
exit 1
fi

if [[ ! -f ~/.config/phoniebox/gpio_settings.ini ]]; then
mkdir -p ~/.config/phoniebox && cp /example_configs/gpio_settings.ini ~/.config/phoniebox/gpio_settings.ini
if [[ ! -f /home/pi/RPi-Jukebox-RFID/settings/gpio_settings.ini ]]; then
cp /home/pi/RPi-Jukebox-RFID/misc/sampleconfigs/gpio_settings.ini.sample /home/pi/RPi-Jukebox-RFID/settings/gpio_settings.ini
fi

echo 'disable old services: phoniebox-gpio-buttons and phoniebox-rotary-encoder'
Expand Down
28 changes: 22 additions & 6 deletions components/gpio_control/test/test_SimpleButton.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

@pytest.fixture
def simple_button():
mockedAction.reset_mock()

return SimpleButton(pin, action=mockedAction, name='TestButton',
bouncetime=500, edge=GPIO.FALLING)

Expand All @@ -22,16 +24,30 @@ def test_init(self):
bouncetime=500, edge=GPIO.FALLING)

def test_callback(self, simple_button):
simple_button.callbackFunctionHandler()(simple_button.pin)
mockedAction.asser_called_once()
simple_button.callbackFunctionHandler(simple_button.pin)
mockedAction.assert_called_once_with()

def test_callback_without_pin_argument(self, simple_button):
simple_button.callbackFunctionHandler()
mockedAction.assert_called_once_with()

def test_callback_with_wrong_pin_argument(self, simple_button):
simple_button.callbackFunctionHandler(simple_button.pin + 1)
mockedAction.assert_called_once_with(simple_button.pin + 1)

def test_callback_with_more_arguments(self, simple_button):
simple_button.callbackFunctionHandler(simple_button.pin, 5)
mockedAction.assert_called_once_with(5)

def test_change_when_pressed(self, simple_button):
mockedAction.asser_called_once()
simple_button.callbackFunctionHandler(simple_button.pin, 5)

newMockedAction = MagicMock()
simple_button.when_pressed = newMockedAction
simple_button.callbackFunctionHandler()(simple_button.pin)
newMockedAction.asser_called_once()
mockedAction.asser_called_once()
simple_button.callbackFunctionHandler(simple_button.pin)

newMockedAction.assert_called_once_with()
mockedAction.assert_called_once_with(5)

def test_hold(self, simple_button):
GPIO.LOW = 0
Expand Down
3 changes: 3 additions & 0 deletions components/rfid-reader/RC522/setup_rc522.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ question "Continue"
printf "Installing Python requirements for RC522...\n"
sudo python3 -m pip install --upgrade --force-reinstall -q -r "${JUKEBOX_HOME_DIR}"/components/rfid-reader/RC522/requirements.txt

printf "Activating SPI...\n"
sudo raspi-config nonint do_spi 0

printf "Configure RFID reader in Phoniebox...\n"
cp "${JUKEBOX_HOME_DIR}"/scripts/Reader.py.experimental "${JUKEBOX_HOME_DIR}"/scripts/Reader.py
printf "MFRC522" > "${JUKEBOX_HOME_DIR}"/scripts/deviceName.txt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def processCmd(command, parameter):
elif command == "gpio":
parameter = parameter.lower()
if parameter == "start" or parameter == "stop":
subprocess.call(["sudo /bin/systemctl " + parameter + " phoniebox-gpio-buttons.service"], shell=True)
subprocess.call(["sudo /bin/systemctl " + parameter + " phoniebox-gpio-control.service"], shell=True)
else:
print(" --> Expecting parameter start or stop")

Expand Down Expand Up @@ -331,7 +331,7 @@ def fetchData():

# fetch service states
result["rfid"] = isServiceRunning("phoniebox-rfid-reader.service")
result["gpio"] = isServiceRunning("phoniebox-gpio-buttons.service")
result["gpio"] = isServiceRunning("phoniebox-gpio-control.service")

# fetch linux jobs
result["remaining_stopafter"] = str(linux_job_remaining("s"))
Expand Down
63 changes: 45 additions & 18 deletions htdocs/api/player.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
*/
$debugLoggingConf = parse_ini_file("../../settings/debugLogging.conf");

if($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n# WebApp API # " . __FILE__ , FILE_APPEND | LOCK_EX);
file_put_contents("../../logs/debug.log", "\n # \$_SERVER['REQUEST_METHOD']: " . $_SERVER['REQUEST_METHOD'] , FILE_APPEND | LOCK_EX);
if ($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n# WebApp API # " . __FILE__, FILE_APPEND | LOCK_EX);
file_put_contents("../../logs/debug.log", "\n # \$_SERVER['REQUEST_METHOD']: " . $_SERVER['REQUEST_METHOD'], FILE_APPEND | LOCK_EX);
}
if ($_SERVER['REQUEST_METHOD'] === 'PUT') {
handlePut();
Expand All @@ -27,19 +27,21 @@

function handlePut() {
global $debugLoggingConf;
if($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n # function handlePut() " , FILE_APPEND | LOCK_EX);
if ($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n # function handlePut() ", FILE_APPEND | LOCK_EX);
}

$body = file_get_contents('php://input');
$json = json_decode(trim($body), TRUE);
if($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n # \$json['command']:".$json['command'] , FILE_APPEND | LOCK_EX);
if ($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n # \$json['command']:" . $json['command'], FILE_APPEND | LOCK_EX);
}
$inputCommand = $json['command'];
$inputValue = $json['value'] ?? "";
if ($inputCommand != null) {
$controlsCommand = determineCommand($inputCommand);
$execCommand = "playout_controls.sh {$controlsCommand}";
$controlsValue = $inputValue !== "" ? " -v=" . ((float)$inputValue) : "";
$execCommand = "playout_controls.sh {$controlsCommand}{$controlsValue}";
execScript($execCommand);
} else {
echo "Body is missing command";
Expand All @@ -49,10 +51,10 @@ function handlePut() {

function handleGet() {
global $debugLoggingConf;
$statusCommand = "echo 'status\ncurrentsong\nclose' | nc -w 1 localhost 6600";
$statusCommand = "echo 'status\ncurrentsong\nclose' | nc -w 1 localhost 6600";
$commandResponseList = execSuccessfully($statusCommand);
$responseList = array();
forEach($commandResponseList as $commandResponse) {
forEach ($commandResponseList as $commandResponse) {
preg_match("/(?P<key>.+?): (?P<value>.*)/", $commandResponse, $match);
if ($match) {
$responseList[strtolower($match['key'])] = $match['value'];
Expand All @@ -61,11 +63,34 @@ function handleGet() {
// get volume separately from mpd, because we might use amixer to control volume
$command = "playout_controls.sh -c=getvolume";
$output = execScript($command);
$responseList['volume'] = implode('\n', $output);

if($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n # function handleGet() " , FILE_APPEND | LOCK_EX);
file_put_contents("../../logs/debug.log", "\n\$responseList: " . json_encode($responseList) . $_SERVER['REQUEST_METHOD'] , FILE_APPEND | LOCK_EX);
$responseList['volume'] = implode('\n', $output);

$command = "playout_controls.sh -c=getchapters";
$output = execScript($command);
$jsonChapters = trim(implode("\n", $output));
$chapters = @json_decode($jsonChapters, true);

$currentChapterIndex = null;
$mappedChapters = array_filter(array_map(function($chapter) use($responseList, &$currentChapterIndex) {
static $i = 1;
if(isset($chapter["start_time"], $chapter["end_time"])) {
$start = (double)$chapter["start_time"];
$end = (double)$chapter["end_time"];

return [
"name" => $chapter["tags"]["title"] ?? $i++,
"start" => round($start, 3),
"length" => round($end - $start, 3)
];
}
return null;
}, $chapters["chapters"] ?? []));

$responseList['chapters'] = $mappedChapters;

if ($debugLoggingConf['DEBUG_WebApp_API'] == "TRUE") {
file_put_contents("../../logs/debug.log", "\n # function handleGet() ", FILE_APPEND | LOCK_EX);
file_put_contents("../../logs/debug.log", "\n\$responseList: " . json_encode($responseList) . $_SERVER['REQUEST_METHOD'], FILE_APPEND | LOCK_EX);
}

header('Content-Type: application/json');
Expand Down Expand Up @@ -99,14 +124,16 @@ function determineCommand($body) {
case 'seekAhead':
//return '-c=playerprev -c=playerseek -v=+15';
return '-c=playerseek -v=+15';
case 'seekPosition':
return '-c=playerseek';
case 'stop':
return '-c=playerstop';
case 'mute':
return'-c=mute';
return '-c=mute';
case 'volumeup':
return'-c=volumeup';
return '-c=volumeup';
case 'volumedown':
return'-c=volumedown';
return '-c=volumedown';
}
echo "Unknown command {$body}";
http_response_code(400);
Expand Down
1 change: 1 addition & 0 deletions htdocs/inc.addSystemInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading

0 comments on commit 9dc8d0d

Please sign in to comment.