mirror of
https://github.com/anikeen-com/print-cli.git
synced 2026-03-13 13:46:07 +00:00
Add autowire
Add logs command Improve print jobs handling Improve installation/documentation
This commit is contained in:
90
app/Commands/Autowire.php
Normal file
90
app/Commands/Autowire.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Commands;
|
||||||
|
|
||||||
|
use App\Support\PrinterManager;
|
||||||
|
use App\Traits\HasConfig;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use LaravelZero\Framework\Commands\Command;
|
||||||
|
use Smalot\Cups\Model\Printer;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class Autowire extends Command
|
||||||
|
{
|
||||||
|
use HasConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'autowire {--init : Initialize the configuration when no config file exists}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Automatically wire up the application';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle(PrinterManager $manager): int
|
||||||
|
{
|
||||||
|
$this->info('Autowiring the application...');
|
||||||
|
|
||||||
|
$printers = $manager->getList()->map(fn(Printer $printer) => [
|
||||||
|
'name' => $printer->getName(),
|
||||||
|
'status' => $printer->getStatus(),
|
||||||
|
'attributes' => $printer->getAttributes(),
|
||||||
|
'uri' => $printer->getUri(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($this->option('init') && !file_exists($this->getYamlFilename())) {
|
||||||
|
$response = Http::acceptJson()->post('https://events.anikeen.com/api/printers/autoinit', [
|
||||||
|
'hostname' => gethostname(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$this->setConfig($response->json());
|
||||||
|
} else {
|
||||||
|
$this->warn('Unable to auto initialize configuration! Please use `print-cli init` to create a configuration file.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$contig = $this->getConfig(expectedVersion: 2);
|
||||||
|
$response = Http::acceptJson()->patch(sprintf('%s/api/printers/autowire', $contig->getBaseUrl()), [
|
||||||
|
'id' => $contig->getId(),
|
||||||
|
'hostname' => gethostname(),
|
||||||
|
'printers' => $printers->toArray(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$newPrinters = $response->json('printers', []);
|
||||||
|
if (empty($newPrinters)) {
|
||||||
|
$this->info('No new printers found to autowire.');
|
||||||
|
} else {
|
||||||
|
foreach ($newPrinters as $printer) {
|
||||||
|
$this->info(sprintf('Printer: %s', $printer['uri']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->setConfig([
|
||||||
|
...$contig->toArray(),
|
||||||
|
'printers' => $newPrinters,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
throw new Exception('Failed to autowire printers: ' . $response->body());
|
||||||
|
}
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
$this->error('Failed to autowire printers: ' . $exception->getMessage());
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Autowiring completed successfully.');
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,17 +2,18 @@
|
|||||||
|
|
||||||
namespace App\Commands;
|
namespace App\Commands;
|
||||||
|
|
||||||
|
use App\Traits\HasConfig;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use LaravelZero\Framework\Commands\Command;
|
use LaravelZero\Framework\Commands\Command;
|
||||||
use Smalot\Cups\Builder\Builder;
|
use Smalot\Cups\Builder\Builder;
|
||||||
use Smalot\Cups\Manager\PrinterManager;
|
use Smalot\Cups\Manager\PrinterManager;
|
||||||
use Smalot\Cups\Model\Printer;
|
|
||||||
use Smalot\Cups\Transport\Client;
|
use Smalot\Cups\Transport\Client;
|
||||||
use Smalot\Cups\Transport\ResponseParser;
|
use Smalot\Cups\Transport\ResponseParser;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
|
|
||||||
class InitCommand extends Command
|
class Init extends Command
|
||||||
{
|
{
|
||||||
|
use HasConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
*
|
*
|
||||||
@@ -33,7 +34,6 @@ class InitCommand extends Command
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$username = getenv('USER') ?: get_current_user();
|
$username = getenv('USER') ?: get_current_user();
|
||||||
$home = getenv('HOME');
|
|
||||||
|
|
||||||
$client = new Client();
|
$client = new Client();
|
||||||
$builder = new Builder();
|
$builder = new Builder();
|
||||||
@@ -48,8 +48,10 @@ class InitCommand extends Command
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->info('Please register printers first at:');
|
$this->info('Please register the print-server first at:');
|
||||||
$this->info('https://events.anikeen.com/console/resources/printers');
|
$this->info('https://events.anikeen.com/console/resources/print-servers');
|
||||||
|
|
||||||
|
$id = $this->ask('What is your print-server ID?');
|
||||||
|
|
||||||
$password = $this->ask('What is your password?', match ($username) {
|
$password = $this->ask('What is your password?', match ($username) {
|
||||||
'print-cli' => 'print-cli',
|
'print-cli' => 'print-cli',
|
||||||
@@ -57,36 +59,14 @@ class InitCommand extends Command
|
|||||||
default => null,
|
default => null,
|
||||||
});
|
});
|
||||||
|
|
||||||
$filename = $home . '/print-cli.yml';
|
$this->setConfig([
|
||||||
|
'version' => 2,
|
||||||
$yaml = Yaml::dump(
|
'id' => $id,
|
||||||
input: [
|
'base_url' => 'https://events.anikeen.com',
|
||||||
'base_url' => 'https://events.anikeen.com',
|
'default_credentials' => [
|
||||||
'printers' => $printers->map(function (Printer $printer) use ($username, $password) {
|
'username' => $username,
|
||||||
$attributes = $printer->getAttributes();
|
'password' => $password,
|
||||||
|
|
||||||
$id = $this->ask(sprintf('What is your ID for %s?', $printer->getName()));
|
|
||||||
|
|
||||||
return [
|
|
||||||
'id' => $id,
|
|
||||||
'name' => $printer->getName(),
|
|
||||||
'driver' => 'cups',
|
|
||||||
'address' => $attributes['printer-uri-supported'][0],
|
|
||||||
'username' => $username,
|
|
||||||
'password' => $password,
|
|
||||||
];
|
|
||||||
})->toArray(),
|
|
||||||
],
|
],
|
||||||
inline: 100,
|
]);
|
||||||
indent: 2,
|
|
||||||
flags: Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK
|
|
||||||
);
|
|
||||||
|
|
||||||
file_put_contents(
|
|
||||||
filename: $filename,
|
|
||||||
data: preg_replace('/-\n\s+/', '- ', $yaml)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->info(sprintf('Created configuration at %s', $filename));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ namespace App\Commands;
|
|||||||
|
|
||||||
use LaravelZero\Framework\Commands\Command;
|
use LaravelZero\Framework\Commands\Command;
|
||||||
|
|
||||||
class InitSupervisorCommand extends Command
|
class InitSupervisor extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
@@ -34,8 +34,8 @@ directory = $home
|
|||||||
command = /usr/bin/php $home/.config/composer/vendor/bin/print-cli serve
|
command = /usr/bin/php $home/.config/composer/vendor/bin/print-cli serve
|
||||||
autostart = true
|
autostart = true
|
||||||
autorestart = true
|
autorestart = true
|
||||||
stderr_logfile = /var/log/print-cli.err.log
|
redirect_stderr = true
|
||||||
stdout_logfile = /var/log/print-cli.out.log
|
stdout_logfile = /var/log/print-cli.log
|
||||||
stopwaitsecs = 3600
|
stopwaitsecs = 3600
|
||||||
user = $username
|
user = $username
|
||||||
INI;
|
INI;
|
||||||
32
app/Commands/InitWireguard.php
Normal file
32
app/Commands/InitWireguard.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Commands;
|
||||||
|
|
||||||
|
use App\Support\PrinterManager;
|
||||||
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
|
use LaravelZero\Framework\Commands\Command;
|
||||||
|
|
||||||
|
class InitWireguard extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'init:wireguard';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Initialize WireGuard configuration';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle(PrinterManager $printer)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
64
app/Commands/Logs.php
Normal file
64
app/Commands/Logs.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Commands;
|
||||||
|
|
||||||
|
use App\Traits\HasConfig;
|
||||||
|
use LaravelZero\Framework\Commands\Command;
|
||||||
|
|
||||||
|
class Logs extends Command
|
||||||
|
{
|
||||||
|
use HasConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'logs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Display the print server logs in real-time';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$logFile = '/var/log/print-cli.log';
|
||||||
|
|
||||||
|
if (!file_exists($logFile)) {
|
||||||
|
$this->error('Log file not found. Please ensure the print server is running.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$cmd = "tail -f $logFile";
|
||||||
|
$descriptorspec = [
|
||||||
|
1 => ['pipe', 'w'], // stdout
|
||||||
|
2 => ['pipe', 'w'], // stderr
|
||||||
|
];
|
||||||
|
$process = proc_open($cmd, $descriptorspec, $pipes);
|
||||||
|
|
||||||
|
if (is_resource($process)) {
|
||||||
|
stream_set_blocking($pipes[1], false);
|
||||||
|
stream_set_blocking($pipes[2], false);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
$out = stream_get_contents($pipes[1]);
|
||||||
|
$err = stream_get_contents($pipes[2]);
|
||||||
|
|
||||||
|
if ($out) $this->info(trim($out));
|
||||||
|
if ($err) $this->error(trim($err));
|
||||||
|
|
||||||
|
usleep(200000); // 200ms delay to avoid CPU overuse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never reached, but if you need to stop manually:
|
||||||
|
// fclose($pipes[1]);
|
||||||
|
// fclose($pipes[2]);
|
||||||
|
// proc_close($process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Commands;
|
namespace App\Commands;
|
||||||
|
|
||||||
|
use App\Support\PrinterManager;
|
||||||
use LaravelZero\Framework\Commands\Command;
|
use LaravelZero\Framework\Commands\Command;
|
||||||
use Smalot\Cups\Builder\Builder;
|
|
||||||
use Smalot\Cups\Manager\PrinterManager;
|
|
||||||
use Smalot\Cups\Transport\Client;
|
|
||||||
use Smalot\Cups\Transport\ResponseParser;
|
|
||||||
|
|
||||||
class ListCommand extends Command
|
class Printers extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
@@ -26,20 +23,17 @@ class ListCommand extends Command
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(PrinterManager $printers): int
|
||||||
{
|
{
|
||||||
$client = new Client();
|
$printers = $printers->getList();
|
||||||
$builder = new Builder();
|
|
||||||
$responseParser = new ResponseParser();
|
|
||||||
|
|
||||||
$printerManager = new PrinterManager($builder, $client, $responseParser);
|
if ($printers->isEmpty()) {
|
||||||
|
$this->error('We could not find any printers! Please register them first in CUPS.');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
$printers = $printerManager->getList();
|
$this->info('Printer:');
|
||||||
|
|
||||||
$this->info('Printers:');
|
|
||||||
|
|
||||||
foreach ($printers as $printer) {
|
foreach ($printers as $printer) {
|
||||||
$this->info($printer->getName());
|
$this->info($printer->getName());
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Commands;
|
namespace App\Commands;
|
||||||
|
|
||||||
|
use App\Support\Config;
|
||||||
|
use App\Traits\HasConfig;
|
||||||
use Illuminate\Http\Client\ConnectionException;
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
use Illuminate\Http\Client\RequestException;
|
use Illuminate\Http\Client\RequestException;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
@@ -15,11 +16,12 @@ use Smalot\Cups\Manager\PrinterManager;
|
|||||||
use Smalot\Cups\Model\Job;
|
use Smalot\Cups\Model\Job;
|
||||||
use Smalot\Cups\Transport\Client;
|
use Smalot\Cups\Transport\Client;
|
||||||
use Smalot\Cups\Transport\ResponseParser;
|
use Smalot\Cups\Transport\ResponseParser;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class ServeCommand extends Command
|
class Serve extends Command
|
||||||
{
|
{
|
||||||
|
use HasConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
*
|
*
|
||||||
@@ -34,18 +36,80 @@ class ServeCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected $description = 'Command description';
|
protected $description = 'Command description';
|
||||||
|
|
||||||
|
private $counter = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
$this->info('Starting service...');
|
||||||
$this->serve();
|
$this->monitor();
|
||||||
} catch (Throwable $e) {
|
}
|
||||||
if ($e instanceof RequestException && $e->response->status() === 422) {
|
|
||||||
$this->error('Please check your configuration and try again.');
|
/**
|
||||||
$this->error($e->response->json()['message']);
|
* Monitor the service and handle jobs.
|
||||||
} else {
|
*/
|
||||||
|
private function monitor(): void
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
// autowire every 10 iterations
|
||||||
|
if ($this->counter % 10 === 0) {
|
||||||
|
try {
|
||||||
|
$this->call('autowire', [
|
||||||
|
'--init' => $this->counter === 0, // Initialize only on the first run
|
||||||
|
]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$this->error('Autowire failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$config = $this->getConfig(expectedVersion: 2);
|
||||||
|
$this->fetchJobs($config);
|
||||||
|
sleep(2);
|
||||||
|
} catch (ConnectionException $e) {
|
||||||
|
$this->error('Connection error: ' . $e->getMessage());
|
||||||
|
sleep(2);
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
$this->error('Request error: ' . $e->getMessage());
|
||||||
|
sleep(2);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$this->error('An unexpected error occurred: ' . $e->getMessage());
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws RequestException
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
private function fetchJobs(Config $config): void
|
||||||
|
{
|
||||||
|
$printerIds = $config->getPrinters()->pluck('id')->toArray();
|
||||||
|
$response = Http::acceptJson()->get(sprintf('%s/api/printers/jobs', $config->getBaseUrl()), [
|
||||||
|
'printer_ids' => $printerIds,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
throw new RequestException($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
$jobs = $response->json();
|
||||||
|
|
||||||
|
if (empty($jobs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Printing jobs...');
|
||||||
|
|
||||||
|
foreach ($jobs as $job) {
|
||||||
|
try {
|
||||||
|
$this->handleJob($config, $job);
|
||||||
|
} catch (Throwable $e) {
|
||||||
$this->error($e->getMessage());
|
$this->error($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,80 +119,18 @@ class ServeCommand extends Command
|
|||||||
* @throws RequestException
|
* @throws RequestException
|
||||||
* @throws ConnectionException
|
* @throws ConnectionException
|
||||||
*/
|
*/
|
||||||
private function serve(): void
|
private function handleJob(Config $config, array $job): void
|
||||||
{
|
{
|
||||||
$this->info('Starting service...');
|
$printer = $config->getPrinters()->firstWhere('id', $job['printer_id']);
|
||||||
|
[$username, $password] = $this->getConfig()->getPrinterCredentials($printer);
|
||||||
|
|
||||||
$yaml = $this->getConfiguration();
|
|
||||||
$printerIds = array_map(fn($printer) => $printer['id'], $yaml['printers']);
|
|
||||||
|
|
||||||
$response = Http::acceptJson()->patch(sprintf('%s/api/printers/register', $yaml['base_url']), [
|
|
||||||
'printers' => $yaml['printers'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->throw();
|
|
||||||
|
|
||||||
$this->info('Service started!');
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
$response = Http::acceptJson()->get(sprintf('%s/api/printers/jobs', $yaml['base_url']), [
|
|
||||||
'printer_ids' => $printerIds,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->failed()) {
|
|
||||||
$this->error('Failed to fetch jobs, error: ' . $response->status());
|
|
||||||
sleep(2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$jobs = $response->json();
|
|
||||||
|
|
||||||
if (empty($jobs)) {
|
|
||||||
sleep(2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('Printing jobs...');
|
|
||||||
|
|
||||||
foreach ($jobs as $job) {
|
|
||||||
try {
|
|
||||||
$this->handleJob($job, $yaml);
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
$this->error($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
$this->error($e->getMessage());
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getConfiguration(): array
|
|
||||||
{
|
|
||||||
$this->info('Reading configuration...');
|
|
||||||
$yaml = file_get_contents(getcwd() . '/print-cli.yml');
|
|
||||||
return Yaml::parse($yaml);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws RequestException
|
|
||||||
* @throws ConnectionException
|
|
||||||
*/
|
|
||||||
private function handleJob(array $job, mixed $yaml): void
|
|
||||||
{
|
|
||||||
$printer = Collection::make($yaml['printers'])->firstWhere('id', $job['printer_id']);
|
|
||||||
if (!empty($job['data']['preview'])) {
|
if (!empty($job['data']['preview'])) {
|
||||||
$this->info(sprintf('Job %s is a preview', $job['id']));
|
$this->info(sprintf('Job %s is a preview', $job['id']));
|
||||||
$this->markCompleted($job, $yaml, 0);
|
$this->markCompleted($config, $job, 0);
|
||||||
return;
|
return;
|
||||||
} elseif (empty($job['file_url'])) {
|
} elseif (empty($job['file_url'])) {
|
||||||
$this->info(sprintf('Job %s has no file', $job['id']));
|
$this->info(sprintf('Job %s has no file', $job['id']));
|
||||||
$this->markFailed($job, $yaml, 'No file provided');
|
$this->markFailed($config, $job, 'No file provided');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,12 +140,12 @@ class ServeCommand extends Command
|
|||||||
$pointWidth = round($paperWidth * 2.83465, 2);
|
$pointWidth = round($paperWidth * 2.83465, 2);
|
||||||
$pointHeight = round($paperHeight * 2.83465, 2);
|
$pointHeight = round($paperHeight * 2.83465, 2);
|
||||||
|
|
||||||
$client = new Client($printer['username'], $printer['password']);
|
$client = new Client($username, $password);
|
||||||
$builder = new Builder();
|
$builder = new Builder();
|
||||||
$responseParser = new ResponseParser();
|
$responseParser = new ResponseParser();
|
||||||
|
|
||||||
$printerManager = new PrinterManager($builder, $client, $responseParser);
|
$printerManager = new PrinterManager($builder, $client, $responseParser);
|
||||||
$printer = $printerManager->findByUri($printer['address']);
|
$printer = $printerManager->findByUri($printer['uri']);
|
||||||
$jobManager = new JobManager($builder, $client, $responseParser);
|
$jobManager = new JobManager($builder, $client, $responseParser);
|
||||||
|
|
||||||
$content = file_get_contents($job['file_url']);
|
$content = file_get_contents($job['file_url']);
|
||||||
@@ -158,12 +160,12 @@ class ServeCommand extends Command
|
|||||||
$printerJob->addAttribute('fit-to-page', true);
|
$printerJob->addAttribute('fit-to-page', true);
|
||||||
|
|
||||||
if (!$jobManager->send($printer, $printerJob)) {
|
if (!$jobManager->send($printer, $printerJob)) {
|
||||||
$this->markFailed($job, $yaml, 'Failed to print job');
|
$this->markFailed($config, $job, 'Failed to print job');
|
||||||
$this->error(sprintf('Failed to print job %s', $job['id']));
|
$this->error(sprintf('Failed to print job %s', $job['id']));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->markCompleted($job, $yaml, $printerJob->getId());
|
$this->markCompleted($config, $job, $printerJob->getId());
|
||||||
|
|
||||||
$this->info(sprintf('Job %s completed as %s', $job['id'], $printerJob->getId()));
|
$this->info(sprintf('Job %s completed as %s', $job['id'], $printerJob->getId()));
|
||||||
}
|
}
|
||||||
@@ -172,11 +174,12 @@ class ServeCommand extends Command
|
|||||||
* @throws RequestException
|
* @throws RequestException
|
||||||
* @throws ConnectionException
|
* @throws ConnectionException
|
||||||
*/
|
*/
|
||||||
private function markCompleted(array $job, mixed $yaml, int $jobId): void
|
private function markCompleted(Config $config, array $job, int $jobId): void
|
||||||
{
|
{
|
||||||
$response = Http::acceptJson()->patch(sprintf('%s/api/printers/jobs/%s/complete', $yaml['base_url'], $job['id']), [
|
$response = Http::acceptJson()
|
||||||
'job_id' => $jobId,
|
->patch(sprintf('%s/api/printers/jobs/%s/complete', $config->getBaseUrl(), $job['id']), [
|
||||||
]);
|
'job_id' => $jobId,
|
||||||
|
]);
|
||||||
$response->throw();
|
$response->throw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +187,12 @@ class ServeCommand extends Command
|
|||||||
* @throws RequestException
|
* @throws RequestException
|
||||||
* @throws ConnectionException
|
* @throws ConnectionException
|
||||||
*/
|
*/
|
||||||
private function markFailed(array $job, mixed $yaml, string $reason): void
|
private function markFailed(Config $config, array $job, string $reason): void
|
||||||
{
|
{
|
||||||
$response = Http::acceptJson()->patch(sprintf('%s/api/printers/jobs/%s/fail', $yaml['base_url'], $job['id']), [
|
Http::acceptJson()
|
||||||
'reason' => $reason,
|
->patch(sprintf('%s/api/printers/jobs/%s/fail', $config->getBaseUrl(), $job['id']), [
|
||||||
]);
|
'reason' => $reason,
|
||||||
$response->throw();
|
])
|
||||||
|
->throw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App;
|
|
||||||
|
|
||||||
class Printer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
68
app/Support/Config.php
Normal file
68
app/Support/Config.php
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Support;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
public function __construct(protected array $config)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key, mixed $default = null): mixed
|
||||||
|
{
|
||||||
|
return $this->config[$key] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, mixed $value): void
|
||||||
|
{
|
||||||
|
$this->config[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $key): bool
|
||||||
|
{
|
||||||
|
return array_key_exists($key, $this->config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove(string $key): void
|
||||||
|
{
|
||||||
|
unset($this->config[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->get('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseUrl(): string
|
||||||
|
{
|
||||||
|
return $this->get('base_url');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrinters(): Collection
|
||||||
|
{
|
||||||
|
return Collection::make($this->get('printers', []));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrinterCredentials(array $printer): array
|
||||||
|
{
|
||||||
|
$defaultCredentials = $this->get('default_credentials');
|
||||||
|
|
||||||
|
return [
|
||||||
|
$printer['username'] ?? $defaultCredentials['username'] ?? null,
|
||||||
|
$printer['password'] ?? $defaultCredentials['password'] ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/Support/PrinterManager.php
Normal file
27
app/Support/PrinterManager.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Support;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Smalot\Cups\Builder\Builder;
|
||||||
|
use Smalot\Cups\Manager\PrinterManager as CupsPrinterManager;
|
||||||
|
use Smalot\Cups\Transport\Client;
|
||||||
|
use Smalot\Cups\Transport\ResponseParser;
|
||||||
|
|
||||||
|
class PrinterManager
|
||||||
|
{
|
||||||
|
protected CupsPrinterManager $printerManager;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$client = new Client();
|
||||||
|
$builder = new Builder();
|
||||||
|
$responseParser = new ResponseParser();
|
||||||
|
$this->printerManager = new CupsPrinterManager($builder, $client, $responseParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getList(): Collection
|
||||||
|
{
|
||||||
|
return Collection::make($this->printerManager->getList());
|
||||||
|
}
|
||||||
|
}
|
||||||
78
app/Traits/HasConfig.php
Normal file
78
app/Traits/HasConfig.php
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
use App\Support\Config;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use RuntimeException;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin Command
|
||||||
|
*/
|
||||||
|
trait HasConfig
|
||||||
|
{
|
||||||
|
protected function getYamlFilename(): string
|
||||||
|
{
|
||||||
|
$home = getenv('HOME') ?: getenv('USERPROFILE');
|
||||||
|
if (!$home && function_exists('posix_getpwuid')) {
|
||||||
|
$home = posix_getpwuid(posix_getuid())['dir'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$home) {
|
||||||
|
throw new \RuntimeException("Unable to determine user's home directory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('%s/print-cli.yml', $home);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConfig($expectedVersion = null): Config
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$yaml = file_get_contents($this->getYamlFilename());
|
||||||
|
} catch (Throwable) {
|
||||||
|
throw new RuntimeException(sprintf(
|
||||||
|
'Unable to read configuration file %s',
|
||||||
|
$this->getYamlFilename(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = Yaml::parse($yaml);
|
||||||
|
|
||||||
|
if ($expectedVersion !== null) {
|
||||||
|
if (!isset($config['version'])) {
|
||||||
|
throw new RuntimeException('Configuration file does not have a version.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config['version'] !== $expectedVersion) {
|
||||||
|
throw new RuntimeException(sprintf(
|
||||||
|
'Configuration file version %s does not match expected version %s.',
|
||||||
|
$config['version'],
|
||||||
|
$expectedVersion
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($config['base_url'])) {
|
||||||
|
throw new RuntimeException('Configuration file does not have a base_url.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Config($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setConfig(array $config): void
|
||||||
|
{
|
||||||
|
$yaml = Yaml::dump(
|
||||||
|
input: $config,
|
||||||
|
inline: 100,
|
||||||
|
indent: 2,
|
||||||
|
flags: Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK
|
||||||
|
);
|
||||||
|
|
||||||
|
file_put_contents(
|
||||||
|
filename: $this->getYamlFilename(),
|
||||||
|
data: preg_replace('/-\n\s+/', '- ', $yaml)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
bin/install
Normal file
40
bin/install
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Prevent running as root
|
||||||
|
if [ "$EUID" -eq 0 ]; then
|
||||||
|
echo "This script must NOT be run as root or with sudo. Please run as a normal user."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stage 1: Install dependencies
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get upgrade -y
|
||||||
|
sudo add-apt-repository -y ppa:ondrej/php
|
||||||
|
sudo apt-get install -y git cups zip unzip supervisor \
|
||||||
|
php-cli php-zip php-curl php-xml php-mbstring \
|
||||||
|
printer-driver-gutenprint
|
||||||
|
|
||||||
|
# Stage 2: Install Composer
|
||||||
|
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||||
|
php composer-setup.php
|
||||||
|
php -r "unlink('composer-setup.php');"
|
||||||
|
sudo mv composer.phar /usr/local/bin/composer
|
||||||
|
|
||||||
|
# Stage 3: Setup Composer global vendor bin directory
|
||||||
|
COMPOSER_BIN_DIR='export PATH="$PATH:$HOME/.config/composer/vendor/bin"'
|
||||||
|
grep -qxF "$COMPOSER_BIN_DIR" ~/.bashrc || echo "$COMPOSER_BIN_DIR" >> ~/.bashrc
|
||||||
|
|
||||||
|
# Stage 4: Configure CUPS server
|
||||||
|
sudo cupsctl --remote-admin --remote-any
|
||||||
|
sudo usermod -aG lpadmin "$USER"
|
||||||
|
sudo /etc/init.d/cups restart
|
||||||
|
|
||||||
|
# Stage 5: Install Print CLI application
|
||||||
|
composer global require anikeen/print-cli
|
||||||
|
print-cli init --no-interaction
|
||||||
|
print-cli init:supervisor | sudo tee /etc/supervisor/conf.d/print-cli.conf > /dev/null
|
||||||
|
|
||||||
|
# Stage 6: Start Supervisor service
|
||||||
|
sudo supervisorctl reread
|
||||||
|
sudo supervisorctl update
|
||||||
|
sudo supervisorctl restart print-cli
|
||||||
@@ -21,7 +21,8 @@
|
|||||||
"illuminate/http": "^11.5",
|
"illuminate/http": "^11.5",
|
||||||
"laravel-zero/framework": "^11.0.0",
|
"laravel-zero/framework": "^11.0.0",
|
||||||
"ghostzero/cups-ipp": "^1.0",
|
"ghostzero/cups-ipp": "^1.0",
|
||||||
"symfony/yaml": "^7.1"
|
"symfony/yaml": "^7.1",
|
||||||
|
"ext-posix": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"laravel/pint": "^1.15.2",
|
"laravel/pint": "^1.15.2",
|
||||||
|
|||||||
76
docs/orangepi5plus.md
Normal file
76
docs/orangepi5plus.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
Installing Print-CLI on a Orange Pi 5 Plus is a straightforward process but requires some time to install the necessary
|
||||||
|
packages. This guide will help you to install Print-CLI on a Orange Pi 5 Plus.
|
||||||
|
|
||||||
|
Estimated time: 30-60 minutes
|
||||||
|
|
||||||
|
## Step 1: Install the Orange Pi OS
|
||||||
|
|
||||||
|
Before we start, make sure you have created a bootable SD card with the **Orange Pi 1.2.0 Jammy** image. The
|
||||||
|
simplest way is to use the Balena Etcher which helps you flash the Orange Pi image onto your SD card.
|
||||||
|
|
||||||
|
Recommended configuration:
|
||||||
|
|
||||||
|
- **OS**: Orange Pi 1.2.0 Jammy with Linux 5.10.160-rockchip-rk3588
|
||||||
|
- **Username**: orangepi
|
||||||
|
|
||||||
|
## Step 2: Install Required Packages
|
||||||
|
|
||||||
|
**Tested Printers:**
|
||||||
|
|
||||||
|
- EPSON ET-2750 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
||||||
|
- EPSON ET-2860 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
||||||
|
|
||||||
|
With the Orange Pi OS installed, we need to install the required packages for Print-CLI to work. Run the following
|
||||||
|
command and grab a coffee while the packages are being installed (it may take a while):
|
||||||
|
|
||||||
|
> **Note:** It may ask you for your password during the installation process.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sfL https://print-cli.b-cdn.net/install | bash -
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: Configuration
|
||||||
|
|
||||||
|
After the installation is complete, you can configure your printer and other settings. Just run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
print-cli init
|
||||||
|
```
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
## WLAN
|
||||||
|
|
||||||
|
https://www.makeuseof.com/connect-to-wifi-with-nmcli/
|
||||||
|
|
||||||
|
# Printer Offsets
|
||||||
|
|
||||||
|
### EPSON ET-2750 Series (with Gutenprint @ OrangePI)
|
||||||
|
|
||||||
|
> Some other OS and drivers need other offsets.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"badge": {
|
||||||
|
"offset": {
|
||||||
|
"y": 0,
|
||||||
|
"x": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### EPSON ET-2860 Series (with Gutenprint @ OrangePI)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"badge": {
|
||||||
|
"offset": {
|
||||||
|
"y": -80,
|
||||||
|
"x": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
46
docs/raspberry.md
Normal file
46
docs/raspberry.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
Installing Print-CLI on a Raspberry Pi is a quite simple process but requires some time installing the required
|
||||||
|
packages. This guide will help you to install Print-CLI on a Raspberry Pi.
|
||||||
|
|
||||||
|
Estimated time: 30-60 minutes
|
||||||
|
|
||||||
|
## Step 1: Install the Raspberry Pi OS
|
||||||
|
|
||||||
|
Before we start, make sure you have created a bootable SD card with the **Ubuntu Server 22.04 LTS 64-bit** image. The
|
||||||
|
simplest way is to use the Raspberry Pi Imager which enables you to select an Ubuntu image when flashing your SD card.
|
||||||
|
|
||||||
|
Recommended configuration:
|
||||||
|
|
||||||
|
- **OS**: Ubuntu Server 22.04 LTS 64-bit
|
||||||
|
- **Username**: print-cli
|
||||||
|
|
||||||
|
## Step 2: Install Required Packages
|
||||||
|
|
||||||
|
**Tested Printers:**
|
||||||
|
|
||||||
|
- EPSON ET-2750 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
||||||
|
- EPSON ET-2860 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
||||||
|
|
||||||
|
With the Raspberry Pi OS installed, we need to install the required packages for Print-CLI to work. Run the following
|
||||||
|
command and grab a coffee while the packages are being installed (it may take a while):
|
||||||
|
|
||||||
|
> **Note:** It may ask you for your password during the installation process.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sfL https://print-cli.b-cdn.net/install | bash -
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 3: Configuration
|
||||||
|
|
||||||
|
After the installation is complete, you can configure your printer and other settings. Just run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
print-cli init
|
||||||
|
```
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
## WLAN
|
||||||
|
|
||||||
|
https://www.makeuseof.com/connect-to-wifi-with-nmcli/
|
||||||
179
orangepi5plus.md
179
orangepi5plus.md
@@ -1,179 +0,0 @@
|
|||||||
# Installation
|
|
||||||
|
|
||||||
Installing Print-CLI on a Raspberry Pi is a quite simple process but requires some time installing the required
|
|
||||||
packages. This guide will help you to install Print-CLI on a Raspberry Pi.
|
|
||||||
|
|
||||||
Estimated time: 30-60 minutes
|
|
||||||
|
|
||||||
## Step 1: Install the Raspberry Pi OS
|
|
||||||
|
|
||||||
Before we start, make sure you have created a bootable SD card with the **Ubuntu Server 22.04 LTS 64-bit** image. The
|
|
||||||
simplest way is to use the Raspberry Pi Imager which enables you to select an Ubuntu image when flashing your SD card.
|
|
||||||
|
|
||||||
Recommended configuration:
|
|
||||||
|
|
||||||
- **OS**: Orange Pi 1.2.0 Jammy with Linux 5.10.160-rockchip-rk3588
|
|
||||||
- **Username**: orangepi
|
|
||||||
|
|
||||||
## Step 2: Install Required Packages
|
|
||||||
|
|
||||||
**Tested Printers:**
|
|
||||||
|
|
||||||
- EPSON ET-2750 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
|
||||||
- EPSON ET-2860 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
|
||||||
|
|
||||||
Next, we need to install the required packages for Print-CLI to work. Run the following commands and grab a coffee while
|
|
||||||
the packages are being installed (it may take a while):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt-get update
|
|
||||||
sudo add-apt-repository ppa:ondrej/php
|
|
||||||
sudo apt-get install -y git cups zip unzip supervisor \
|
|
||||||
php-zip php-curl php-xml php-mbstring \
|
|
||||||
printer-driver-gutenprint
|
|
||||||
```
|
|
||||||
|
|
||||||
Install Composer as usual:
|
|
||||||
|
|
||||||
```
|
|
||||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
|
||||||
php composer-setup.php
|
|
||||||
php -r "unlink('composer-setup.php');"
|
|
||||||
sudo mv composer.phar /usr/local/bin/composer
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, add the Composer bin directory to your PATH, so you can run the `print-cli` command from anywhere:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
echo 'export PATH="$PATH:$HOME/.config/composer/vendor/bin"' >> ~/.bashrc
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 3: Ensure CUPS is Running
|
|
||||||
|
|
||||||
Now we need to ensure that the CUPS service is running. CUPS is the printing system used by Print-CLI to send print jobs
|
|
||||||
to the printer. This is the most important step, so make sure you follow it carefully, otherwise, Print-CLI won't work
|
|
||||||
as expected, and you won't be able to print anything.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo cupsctl --remote-admin --remote-any
|
|
||||||
sudo usermod -aG lpadmin orangepi
|
|
||||||
sudo /etc/init.d/cups restart
|
|
||||||
```
|
|
||||||
|
|
||||||
Make sure the CUPS service is running by visiting the following URL in your browser:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://10.20.0.195:631/printers/
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see a page with a list of printers. If you don't see any printers, you may need to add one manually.
|
|
||||||
|
|
||||||
Ensure that you can print a test page by clicking on the printer name and selecting "Print Test Page".
|
|
||||||
|
|
||||||
### Find the Printer Address
|
|
||||||
|
|
||||||
To find the printer address, visit your Printers page in CUPS, and click on the printer name. The address in the browser
|
|
||||||
should look like this:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://10.20.0.195:631/printers/EPSON_ET_2720_Series
|
|
||||||
```
|
|
||||||
|
|
||||||
It contains the Name of the printer, which is the `printer-name` part. You can use this address in the configuration
|
|
||||||
file for Print-CLI. In most cases, just replace the `https` with `ipp` and replace the ip to `127.0.0.1`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
ipp://127.0.0.1:631/printers/EPSON_ET_2720_Series
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 4: Install Print-CLI
|
|
||||||
|
|
||||||
So far, we have installed all the required packages and ensured that CUPS is running. Now we can install Print-CLI using
|
|
||||||
Composer, the PHP package manager. Run the following command to install Print-CLI globally:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
composer global require anikeen/print-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also use the same command to update Print-CLI to the latest version:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
composer global require anikeen/print-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 5: Configure Print-CLI
|
|
||||||
|
|
||||||
With the latest version, you can automatically create your `/home/orangepi/print-cli.yml` with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
print-cli init
|
|
||||||
```
|
|
||||||
|
|
||||||
To test the configuration, run the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
print-cli serve
|
|
||||||
```
|
|
||||||
|
|
||||||
If everything is configured correctly, you should see the following output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Starting service...
|
|
||||||
Reading configuration...
|
|
||||||
Service started!
|
|
||||||
```
|
|
||||||
|
|
||||||
You can exit the service by pressing `Ctrl+C`.
|
|
||||||
|
|
||||||
## Step 6: Supervisor Configuration
|
|
||||||
|
|
||||||
To run Print-CLI as a service, we can use Supervisor. Supervisor is a process control system that allows you to monitor
|
|
||||||
and control a number of processes on UNIX-like operating systems.
|
|
||||||
|
|
||||||
Create a new configuration file `/etc/supervisor/conf.d/print-cli.conf`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
print-cli init:supervisor | sudo tee /etc/supervisor/conf.d/print-cli.conf > /dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, update Supervisor to read the new configuration file and start the Print-CLI service:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo supervisorctl reread
|
|
||||||
sudo supervisorctl update
|
|
||||||
sudo supervisorctl start print-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
## WLAN
|
|
||||||
|
|
||||||
https://www.makeuseof.com/connect-to-wifi-with-nmcli/
|
|
||||||
|
|
||||||
## Printer Offsets
|
|
||||||
|
|
||||||
### EPSON ET-2750 Series (with Gutenprint @ OrangePI)
|
|
||||||
|
|
||||||
> Some other OS and drivers need other offsets.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"badge": {
|
|
||||||
"offset": {
|
|
||||||
"y": 0,
|
|
||||||
"x": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### EPSON ET-2860 Series (with Gutenprint @ OrangePI)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"badge": {
|
|
||||||
"offset": {
|
|
||||||
"y": -80,
|
|
||||||
"x": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
152
raspberry.md
152
raspberry.md
@@ -1,152 +0,0 @@
|
|||||||
# Installation
|
|
||||||
|
|
||||||
Installing Print-CLI on a Raspberry Pi is a quite simple process but requires some time installing the required
|
|
||||||
packages. This guide will help you to install Print-CLI on a Raspberry Pi.
|
|
||||||
|
|
||||||
Estimated time: 30-60 minutes
|
|
||||||
|
|
||||||
## Step 1: Install the Raspberry Pi OS
|
|
||||||
|
|
||||||
Before we start, make sure you have created a bootable SD card with the **Ubuntu Server 22.04 LTS 64-bit** image. The
|
|
||||||
simplest way is to use the Raspberry Pi Imager which enables you to select an Ubuntu image when flashing your SD card.
|
|
||||||
|
|
||||||
Recommended configuration:
|
|
||||||
|
|
||||||
- **OS**: Ubuntu Server 22.04 LTS 64-bit
|
|
||||||
- **Username**: print-cli
|
|
||||||
|
|
||||||
## Step 2: Install Required Packages
|
|
||||||
|
|
||||||
**Tested Printers:**
|
|
||||||
|
|
||||||
- EPSON ET-2750 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
|
||||||
- EPSON ET-2860 Series with driver: Epson Expression ET-2750 EcoTank - CUPS+Gutenprint v5.3.3 (color)
|
|
||||||
|
|
||||||
Next, we need to install the required packages for Print-CLI to work. Run the following commands and grab a coffee while
|
|
||||||
the packages are being installed (it may take a while):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get upgrade -y
|
|
||||||
sudo add-apt-repository ppa:ondrej/php
|
|
||||||
sudo apt-get install -y git cups zip unzip supervisor \
|
|
||||||
php-cli php-zip php-curl php-xml php-mbstring \
|
|
||||||
printer-driver-gutenprint
|
|
||||||
```
|
|
||||||
|
|
||||||
Install Composer as usual:
|
|
||||||
|
|
||||||
```
|
|
||||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
|
||||||
php composer-setup.php
|
|
||||||
php -r "unlink('composer-setup.php');"
|
|
||||||
sudo mv composer.phar /usr/local/bin/composer
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, add the Composer bin directory to your PATH, so you can run the `print-cli` command from anywhere:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
echo 'export PATH="$PATH:$HOME/.config/composer/vendor/bin"' >> ~/.bashrc
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 3: Ensure CUPS is Running
|
|
||||||
|
|
||||||
Now we need to ensure that the CUPS service is running. CUPS is the printing system used by Print-CLI to send print jobs
|
|
||||||
to the printer. This is the most important step, so make sure you follow it carefully, otherwise, Print-CLI won't work
|
|
||||||
as expected, and you won't be able to print anything.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo cupsctl --remote-admin --remote-any
|
|
||||||
sudo usermod -aG lpadmin print-cli
|
|
||||||
sudo /etc/init.d/cups restart
|
|
||||||
```
|
|
||||||
|
|
||||||
Make sure the CUPS service is running by visiting the following URL in your browser:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://10.20.0.195:631/printers/
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see a page with a list of printers. If you don't see any printers, you may need to add one manually.
|
|
||||||
|
|
||||||
Ensure that you can print a test page by clicking on the printer name and selecting "Print Test Page".
|
|
||||||
|
|
||||||
### Find the Printer Address
|
|
||||||
|
|
||||||
To find the printer address, visit your Printers page in CUPS, and click on the printer name. The address in the browser
|
|
||||||
should look like this:
|
|
||||||
|
|
||||||
```text
|
|
||||||
https://10.20.0.195:631/printers/EPSON_ET_2720_Series
|
|
||||||
```
|
|
||||||
|
|
||||||
It contains the Name of the printer, which is the `printer-name` part. You can use this address in the configuration
|
|
||||||
file for Print-CLI. In most cases, just replace the `https` with `ipp` and replace the ip to `127.0.0.1`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
ipp://127.0.0.1:631/printers/EPSON_ET_2720_Series
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 4: Install Print-CLI
|
|
||||||
|
|
||||||
So far, we have installed all the required packages and ensured that CUPS is running. Now we can install Print-CLI using
|
|
||||||
Composer, the PHP package manager. Run the following command to install Print-CLI globally:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
composer global require anikeen/print-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also use the same command to update Print-CLI to the latest version:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
composer global require anikeen/print-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
## Step 5: Configure Print-CLI
|
|
||||||
|
|
||||||
With the latest version, you can automatically create your `/home/print-cli/print-cli.yml` with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
print-cli init
|
|
||||||
```
|
|
||||||
|
|
||||||
To test the configuration, run the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
print-cli serve
|
|
||||||
```
|
|
||||||
|
|
||||||
If everything is configured correctly, you should see the following output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Starting service...
|
|
||||||
Reading configuration...
|
|
||||||
Service started!
|
|
||||||
```
|
|
||||||
|
|
||||||
You can exit the service by pressing `Ctrl+C`.
|
|
||||||
|
|
||||||
## Step 6: Supervisor Configuration
|
|
||||||
|
|
||||||
To run Print-CLI as a service, we can use Supervisor. Supervisor is a process control system that allows you to monitor
|
|
||||||
and control a number of processes on UNIX-like operating systems.
|
|
||||||
|
|
||||||
Create a new configuration file `/etc/supervisor/conf.d/print-cli.conf`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
print-cli init:supervisor | sudo tee /etc/supervisor/conf.d/print-cli.conf > /dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, update Supervisor to read the new configuration file and start the Print-CLI service:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo supervisorctl reread
|
|
||||||
sudo supervisorctl update
|
|
||||||
sudo supervisorctl start print-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
# Troubeshooting
|
|
||||||
|
|
||||||
## WLAN
|
|
||||||
|
|
||||||
https://www.makeuseof.com/connect-to-wifi-with-nmcli/
|
|
||||||
Reference in New Issue
Block a user