sbs20 / scanservjs

SANE scanner nodejs web ui
https://sbs20.github.io/scanservjs/
GNU General Public License v2.0
686 stars 137 forks source link

[Guide] Setup an HP Printer that requires a plugin #724

Open FoxxMD opened 2 months ago

FoxxMD commented 2 months ago

If you use an HP All-In-One printer or a LaserJet or MFP-variant HP printer you may need a plugin, along with the actual hpaio driver, in order to get your scanner to work.

Check this list to see if the plugin is Required for your printer

This guide will presume you are using the docker installation for scanservjs but should be applicable to other installations with some modification.

How Do I Know?

If your printer doesn't work out the box the first thing you should do is verify connectivity within the container using scanimage -L or consult the other troubleshooting steps.

If your printer does show up with scanimage -L but is not displaying when being added with the normal methods (ENVs or on startup using SCANIMAGE) then the next step is manually add your device to force scanservjs to try to connect. Using the steps from https://github.com/sbs20/scanservjs/issues/701#issue-2004726363 :

Modify config

Make a copy of config.default.js. In the afterConfig(config) {} block add a statement to push your device to the config like so:

module.exports = {
  // bunch of comments and stuff in the default config...
  afterConfig(config) {
        //more comments...
        //
       // add your device here
        config.devices.push('hpaio:/net/photosmart_prem_c410_series?ip=192.168.99.134&queue=false');
  }
}

Save the modified file as config.local.js somewhere

Mount a folder to config dir in container

Use the documented Volume Mappings and mount the host directory with your config.local.js to /etc/scanservjs in the container. Then (re)start the container and visit the UI.

Driver Needed?

If you see an error that contains invalid argument then you need a docker image with the libsane-hpaio driver installed! The Dockerfile contains a stage specific for installing this driver if you want to build your own. Otherwise, check dockerhub for images that are built for this stage/driver. I am personally using jyavorksy/scanservjs-hplip.

Recreate your container with the hpaio-variant docker image (with all the same settings).

Plugin Needed?

If you see an error when visiting the UI (or in logs) that contains error duing device i/o then you need the HPLIP Binary Plug-In. The plug-in version you need will match the version of the libsane-hpaio driver you have installed. As of this post scanservjs is using debian bookworm with the 3.22.10 driver.

Driver Download and Install

Find the matching plugin version from the plugin download page (hplip-3.22.10-plugin.run for debian bookworm) and download it somewhere.

In your container map a new volume where you access the plugin. Example -v /opt/blobs:/home/yourUser/hpPrinter will mount the hpPrinter folder to /opt/blobs in the container.

Copy the downloaded plugin into the host folder hpPrinter. Now you can docker exec into container to install the plugin. In the container run:

hp-plugin -p /opt/blobs/hplip-3.22.10-plugin.run

This will initiate the interactive installer to install the plugin. You'll need to answer Y to a few questions. If the installer finishes with done. you are done! Restart the container and refresh devices in the UI to see your printer.

If you recreate the container (or update the image) you will need to repeat the installation process.

Convenience Script

This script can be created alongside the plugin to make installation less annoying:

#!/bin/sh
yes y | hp-plugin -p /opt/blobs/hplip-3.22.10-plugin.run

Save the script as pluginInstall.sh and run chmod +x pluginInstall.sh to make it executable. Put it in the same folder as the plugin and now you can exec into the shell (or use docker run) and do /opt/blobs/pluginInstall.sh to make the plug installation unattended.

davidclaeysquinones commented 2 months ago

I've been able to set up a HP Envy Inspire 7200 and a HP Envy Pro 6442 with the standard Docker image. A while ago I wrote this article about the subject. In short I installed the driver on the host and used the SANED_NET_HOSTS and AIRSCAN_DEVICES environment variables.

Example docker compose :

version: "3"
services:
  scanservjs:
    image: sbs20/scanservjs:latest
    privileged: true
    environment:
      - UID=${UID}
      - GID=${GID}
      - SANED_NET_HOSTS=192.168.0.85
      - AIRSCAN_DEVICES='"HP Envy Inspire 7200" = "http://192.168.0.85/eSCL"'
    volumes:
      - /docker/sane/images:/var/lib/scanservjs/output
      - /docker/sane/config:/etc/scanservjs
      - /var/run/dbus:/var/run/dbus
    ports:
      - ${WEB_PORT}:8080
    restart: unless-stopped

I use some device overrides for display names and specific resolution but I don't need to force my scanner into the configuration.

In the past driver specific tags were available, but they were probably removed because maintaining them is kind of a nightmare. Your proposed method offers the advantage of not affecting the Docker host although I don't dig the deploy ability of this solution. Ideally I would like to not needing to force the configuration and setting the driver up in the container seems prone to failures. Anyway that's my two cents.

Thinking on a broader scale there should be a plugin system that installs the driver you need when you specify it through a parameter. This of course would require quite some work to make it generic enough (I might be up for that challenge) but the problem again is maintenance. The time and resources of the maintainers are finite and to be honest the project has been resting for quite a while. So while someone might be able to make a POC the issue is maintenance.

FoxxMD commented 2 months ago

setting the driver up in the container seems prone to failures...there should be a plugin system that installs the driver you need when you specify it through a parameter.

I agree and this is what I was initially working on code for but the HPLIP Plug-in site notes:

Additionally, it requires the user to read and agree to a license agreement at the time of driver installation.

And the license states:

  1. Copies and Adaptations. You may only make copies or adaptations of the Software for archival purposes or when copying or adaptation is an essential step in the authorized Use of the Software. You must reproduce all copyright notices in the original Software on all copies or adaptations. You may not copy the Software onto any public network.

which isn't explicitly a statement of "you may not redistribute this software" but it's close enough that I think writing code to automate downloading the binary and circumvent user interaction (including reading the agreement) AND including that in a redistributable (prebuilt) docker image is a pretty gray area. This is why i opted to include the bash script separately in this guide instead of just pushing my own docker image with it while checking for a plugin in a specified folder.


I don't dig the deploy ability of this solution. Ideally I would like to not needing to force the configuration

Also agreed and actually it may work with only needing to use SANED_NET_HOSTS after driver/plugin installation but for the purpose of this guide I want the user to be able to get a positive result that the issue is driver related rather than connectivity related and the easiest way to do that is to force scanserv to emit an error by forcing a device -- in my initial testing using SANED_NET_HOSTS/AIRSCAN just had scanserv silently fail to include the device.

davidclaeysquinones commented 2 months ago

As long as your code doesn't embed HP's code I don't think they can claim you're copying or redistributing it. For compliance reasons it would enough to state that by using said plugin you agree to the user agreement with a link to it. By any means I'm not a lawyer but that is what seems to make sense.

It's a shame that SANED_NET_HOSTS/AIRSCAN doesn't work out for you. Hopefully with the plugin installation it works through SANED_NET_HOSTS .

FoxxMD commented 2 months ago

@davidclaeysquinones I got the automated install script figured out and its available in the PR mentioned above. Tested with my network and I do not need the manual device addition or any ENVs at all anymore. scanservjs detects my scanner using hpaio:// URL out of the box now.

davidclaeysquinones commented 2 months ago

I'm glad to hear you were able to add an installation script. Although I'm not sure how I feel about including it in the main Dockerfile. I think it would be better to make an init directory, so that when you include it through a mapping (or a specific tag) it runs at startup time. This would also allow for separating plugin and driver installation from the project. So that @sbs20 can focus on enhancing the project and adding features (he could include a reference in the documentation) and you and others can focus on maintaining the plugins. I'm not wanting to say where your script should be included since I'm not the maintainer (in the main repo or a plugins repo), I just think it's nice to enable separation of concerns.

In addition note someone not using a HP print probably won't want to install the plugin.

I'm personally wanting to write a script to enable the hplip installation so that at some point I can remove it from my host. Hopefully I get some time to do it at some point since that is a tedious process .
Nice work :)

FoxxMD commented 2 months ago

I think it would be better to make an init directory, so that when you include it through a mapping (or a specific tag) it runs at startup time. This would also allow for separating plugin and driver installation from the project. ... In addition note someone not using a HP print probably won't want to install the plugin.

That is what it is doing, as described in the PR.

If those ENVs are not included on container start then the container is exactly the same as the existing scanservjs image.

The scripts using those ENVs also check for install status before running so they only run once.

I'm personally wanting to write a script to enable the hplip installation

The plugin install script is distro agnostic. If you have the hp driver installed it should be able to determine the matching plugin for you based on output from hp-plugin command which is usually installed along with the driver.

davidclaeysquinones commented 2 months ago

You're right I didn't look at it with enough thought. Now that I had a second look, the environment parameters are only defined in your script. So if someone else wants to install another driver they can make their own environment variable and script. Nice work :).

Now it's up to Sam to determine if he wants to include your script in the main repo or if he only wants to include the modification to have the plugin directory in the Dockerfile and link in the documentation in the repo.

FoxxMD commented 2 months ago

if someone else wants to install another driver they can make their own environment variable and script.

Part of the reason the scripts are in a new /scripts folder is that if the PR is merged I'll introduce another PR that has the entrypoint checking /scripts/user for script files that it'll automatically run on container start.