Skip to content

Commit cbc41c2

Browse files
almostengrFalcon Player
and
Falcon Player
authored
Initial (#20)
* Update issue templates * Added files from FPP template * Updated plugin information, repository links * Created pseudocode for worker; updated links in about * Updated description * #3 send status; updated menu links, repository links * moved common logic to common.php; created settings.php * #14 #12 #3 updated settings form, worker * #3 created request object for server * Refactored worker, created script for background proces * Reorganized project; updated project name and url * created tests * Removed composer files; closed #8 status only sent when sequence changes; Closed #12 h5 second delay implemented; closed #5 status only sent when sequence has changed; added environment selector * added plugin json url to readme * #3 added environment option; #14 updated menu, method visibility * #15 set up composer, GH workflow for automated testing * #16 created automated tests * #16 created automated tests * Automated testing (#18) * Create php.yml * updated phpunit command * updated php unit test and file name * removed code coverage option * #16 removed unused workflow * Updated plugin information * Updated install instructions; plugin information * #16 added tests; moved worker call to separate file for testing * updated workflows * Update daemon to stop logging errors after 5 failures to prevent filling log files * Updated status response with next request; adjusted delays, method names * updated method name, logic for posting status * Removed help directory, updated bug template for FPP * Updated beta environment URL * Updated plugin info URL * updated branch name * Ignore swap files; added immediate and gracefull stop options * multiple updates and bug fixes * created commands for enabling and disabling requests * Updated file name; added command descriptions * updated dependabot; added commands * Update BETA url, removed unused file * Updated test condition; log messages * added link to help documentation * update routes; code cleanup * Updated command descriptions and names * Refactor method; created install and uninstall scripts, constants; disabled workflow task * Updated settings to use configuration file from server * Updated endspoints to website; modified workflow for daemon * refactored commands; modified sending sequences * cleaned up constants; updated logic for status and next request * moved constants from functions; updated calls for admin sequence requests * Updated for jukebox selection; move to commands for worker funtionality * Moved functionality to CommandHandlers * closed #22 converted to commands; added startup and shut down scripts; renamed commands * closed #21 gets next request when necessary * Updated route for adding options * Added PHP version dependency; updated command names --------- Co-authored-by: Falcon Player <fpp@FPP>
1 parent 12c4f07 commit cbc41c2

39 files changed

+2870
-2
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior:
15+
1. Go to '...'
16+
2. Click on '....'
17+
3. Scroll down to '....'
18+
4. See error
19+
20+
**Expected behavior**
21+
A clear and concise description of what you expected to happen.
22+
23+
**Screenshots**
24+
If applicable, add screenshots to help explain your problem.
25+
26+
**FPP information (please complete the following information):**
27+
- Device [e.g. Beaglebone Black, Raspberry Pi]
28+
- Version [e.g. 6.x]
29+
30+
**Additional context**
31+
Add any other context about the problem here.
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.

.github/dependabot.yml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: composer
4+
directory: "/"
5+
schedule:
6+
interval: weekly
7+
open-pull-requests-limit: 5
8+
- package-ecosystem: github-actions
9+
directory: "/"
10+
schedule:
11+
interval: weekly
12+
open-pull-requests-limit: 5

.github/workflows/release.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
on:
2+
release:
3+
types: [published]
4+
5+
jobs:
6+
update_package:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Packagist Update
10+
uses: mnavarrocarter/packagist-update@v1.0.0
11+
with:
12+
username: almostengr
13+
api_token: ${{ secrets.PACKAGIST_TOKEN }}
14+
package_name: almostengr/show-pulse-fpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Run PHPUnit Tests
2+
3+
on:
4+
pull_request:
5+
branches: [ "main" ]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
build:
12+
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Validate composer.json and composer.lock
19+
run: composer validate --strict
20+
21+
- name: Cache Composer packages
22+
id: composer-cache
23+
uses: actions/cache@v3
24+
with:
25+
path: vendor
26+
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
27+
restore-keys: |
28+
${{ runner.os }}-php-
29+
30+
- name: Install dependencies
31+
run: composer install --prefer-dist --no-progress
32+
33+
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
34+
# Docs: https://getcomposer.org/doc/articles/scripts.md
35+
36+
# - name: Run test suite
37+
# run: composer run-script test
38+
39+
- name: Run PHPUnit tests
40+
run: vendor/bin/phpunit --colors=never

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.phpunit.cache
2+
3+
/vendor/
4+
.swp

README.md

+44-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,44 @@
1-
# light-show-guard-plugin
2-
FPP Plugin for Light Show Guard
1+
# Show Pulse Plugin for Falcon Pi Player
2+
3+
Show Pulse plugin allows you to see and remotely controller what happens with your light show. This
4+
plugin is designed to work with Falcon Pi Player.
5+
6+
7+
## Install Plugin
8+
9+
There are two ways to install the plugin. Using FPP user interface or using PHP's Composer.
10+
11+
### Using FPP
12+
13+
To install the plugin to your Falcon Pi Player, go to the Plugins section of the FPP. Then copy and
14+
paste the URL below to install the plugin.
15+
16+
```sh
17+
https://raw.githubusercontent.com/almostengr/show-pulse-fpp/main/pluginInfo.json
18+
```
19+
20+
### Using Composer
21+
22+
Open a terminal or command prompt window, and go to the plugin directory or other directory of your chosing. Then enter the command
23+
24+
```sh
25+
composer require almostengr/show-pulse-fpp
26+
```
27+
28+
## Setup
29+
30+
See the [User Guide](https://lightshowpulse.com/pages/user-guide/fpp-plugin-quick-start) for how
31+
to configure the plugin.
32+
33+
34+
## Version Numbering
35+
36+
The version number for this plugin is in the following format. Using the example of
37+
38+
```txt
39+
5.2024.07.26
40+
```
41+
42+
"5" represents the major Falcon Pi Player version number that the plugin is designed for
43+
44+
"2024.07.26" represents the date, in YYYY-MM-DD format, that the release was created

ShowPulseDaemon.php

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use App\Commands\JukeboxSelectionInsertNextCommandHandler;
6+
use App\Commands\PostStatusToWebsiteCommandHandler;
7+
use App\Commands\ShowPulseConstant;
8+
use Exception;
9+
10+
require_once "commands/InsertNextJukeboxSelectionCommandHandler.php";
11+
require_once "commands/PostStatusToWebsiteCommandHandler.php";
12+
13+
$postStatusCommand = new PostStatusToWebsiteCommandHandler();
14+
$nextSelectionCommand = new JukeboxSelectionInsertNextCommandHandler();
15+
16+
$failureCount = 0;
17+
$delaySeconds = 2;
18+
19+
do {
20+
try {
21+
$postStatusCommand->execute();
22+
$nextSelectionCommand->execute();
23+
24+
sleep(ShowPulseConstant::SLEEP_SHORT_VALUE);
25+
26+
$failureCount = 0;
27+
} catch (Exception $e) {
28+
if ($failureCount < ShowPulseConstant::MAX_FAILURES_ALLOWED) {
29+
$message = $e->getMessage() . " (Attempt $failureCount)";
30+
$postStatusCommand->logError($message);
31+
$failureCount++;
32+
}
33+
34+
$sleepTime = $failureCount * $delaySeconds;
35+
sleep($sleepTime);
36+
}
37+
38+
$daemonFileExists = file_exists(ShowPulseConstant::DAEMON_FILE);
39+
} while ($daemonFileExists);
40+
41+
$postStatusCommand->logError("Daemon stopped.");

about.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<div style="margin:0 auto;"> <br />
2+
<fieldset style="padding: 10px; border: 2px solid #000;">
3+
<legend>Show Pulse Plugin</legend>
4+
<div style="overflow: hidden; padding: 10px;">
5+
<div id='credits'>
6+
<b>Show Pulse Plugin Developed By:</b><br />
7+
<br />
8+
Kenny Robinson (almostengr)<br />
9+
<br />
10+
<a href='https://github.com/almostengr/show-pulse-fpp'>Git Repository</a><br>
11+
<a href='https://github.com/almostengr/show-pulse-fpp/issues'>Bug Reporter</a><br>
12+
<br />
13+
</div>
14+
</div>
15+
</fieldset>
16+
</div>

commands/BaseCommandHandler.php

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<?php
2+
3+
namespace App\Commands;
4+
5+
$commonFile = $testing ? __DIR__ . "/tests/OptFppWwwCommonMock.php" : "/opt/fpp/www/common.php";
6+
require_once $commonFile;
7+
8+
interface ShowPulseCommandHandlerInterface
9+
{
10+
protected function execute();
11+
}
12+
13+
abstract class BaseCommandHandler
14+
{
15+
private $token;
16+
private $showUuid;
17+
private $websiteApiUrl;
18+
19+
protected function fppHttpRequest($route, $method = "GET", $data = null)
20+
{
21+
$headers = array();
22+
23+
array_push($headers, "Authorization: Bearer $this->token");
24+
25+
$url = "https://127.0.0.1/api/";
26+
return $this->httpRequest($url, $route, $method, $data);
27+
}
28+
29+
protected function httpRequest($url, $route, $method = "GET", $data = null)
30+
{
31+
$headers = array();
32+
33+
34+
array_push($headers, "Content-Type: application/json");
35+
array_push($headers, "Accept: application/json");
36+
37+
$url = $url . $route;
38+
39+
$ch = curl_init($url);
40+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
41+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
42+
43+
$method = strtoupper($method);
44+
if ($method === "POST" || $method === "PUT") {
45+
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
46+
}
47+
48+
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
49+
50+
$response = curl_exec($ch);
51+
52+
if ($response === false) {
53+
return $this->logError("cURL error: " . curl_error($ch));
54+
}
55+
56+
curl_close($ch);
57+
58+
if ($response === null) {
59+
return $this->logError("Bad response returned.");
60+
}
61+
62+
return json_decode($response, true);
63+
}
64+
65+
protected function getShowUuid()
66+
{
67+
return $this->showUuid;
68+
}
69+
70+
public function logError($message)
71+
{
72+
$currentDateTime = date('Y-m-d h:i:s A');
73+
error_log("$currentDateTime: $message");
74+
return false;
75+
}
76+
77+
protected function isNullOrEmpty($value)
78+
{
79+
return is_null($value) || empty($value);
80+
}
81+
82+
protected function isNotNullOrEmpty($value)
83+
{
84+
return !$this->isNullOrEmpty($value);
85+
}
86+
87+
protected function loadConfiguration(): bool
88+
{
89+
$configFile = GetDirSetting("uploads") . "/showpulse.json";
90+
$contents = file_get_contents($configFile);
91+
92+
if ($contents === false) {
93+
return $this->logError("Configuration file not found or unable to be loaded. Download configuration file contents from the Light Show Pulse website. Then restart FPPD.");
94+
}
95+
96+
$json = json_decode($contents, false);
97+
98+
$this->showUuid = $json->show_id;
99+
$this->token = $json->token;
100+
$this->websiteApiUrl = $json->host;
101+
return true;
102+
}
103+
104+
protected function getStatusFromFpp()
105+
{
106+
$fppStatus = $this->httpRequest(true, "fppd/status");
107+
108+
if ($this->isNullOrEmpty($fppStatus)) {
109+
return $this->logError("Unable to get latest status from FPP.");
110+
}
111+
112+
return $fppStatus;
113+
}
114+
115+
protected function postStatusToWebsite($statusDto)
116+
{
117+
$response = $this->httpRequest(
118+
false,
119+
"show-statuses/add/" . $this->getShowUuid(),
120+
"POST",
121+
$statusDto
122+
);
123+
124+
if ($response->failed) {
125+
return $this->logError("Unable to update show status. " . $response->message);
126+
}
127+
128+
return $response;
129+
}
130+
}
131+
132+
final class ShowPulseConstant
133+
{
134+
public const FPP_STATUS_IDLE = 0;
135+
public const GRACEFUL_RESTART = "GRACEFUL RESTART";
136+
public const GRACEFUL_SHUTDOWN = "GRACEFUL SHUTDOWN";
137+
public const GRACEFUL_STOP = "GRACEFUL STOP";
138+
public const HIGH_PRIORITY = 10;
139+
public const IMMEDIATE_RESTART = "IMMEDIATE RESTART";
140+
public const IMMEDIATE_SHUTDOWN = "IMMEDIATE SHUTDOWN";
141+
public const IMMEDIATE_STOP = "IMMEDIATE STOP";
142+
public const MAX_FAILURES_ALLOWED = 5;
143+
public const SLEEP_SHORT_VALUE = 5;
144+
public const DAEMON_FILE = "/home/fpp/media/plugins/show-pulse-fpp/daemon.run";
145+
}
146+
147+
final class ShowPulseApiResponseDto
148+
{
149+
public $success;
150+
public $failed;
151+
public $message;
152+
public $data;
153+
}

0 commit comments

Comments
 (0)