barcode-server


Namebarcode-server JSON
Version 2.4.0 PyPI version JSON
download
home_pagehttps://github.com/markusressel/barcode-server
SummaryA simple daemon to expose USB Barcode Scanner data to other services using Websockets, Webhooks or MQTT.
upload_time2023-09-09 13:49:38
maintainer
docs_urlNone
authorMarkus Ressel
requires_python>=3.10,<4.0
licenseAGPL-3.0-or-later
keywords barcode asyncio qrcode http mqtt server websocket websocket
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # barcode-server [![Code Climate](https://codeclimate.com/github/markusressel/barcode-server.svg)](https://codeclimate.com/github/markusressel/barcode-server)

A simple daemon to read barcodes from USB Barcode Scanners
and expose them to other service using HTTP calls, a websocket API or MQTT.

[![asciicast](https://asciinema.org/a/366004.svg)](https://asciinema.org/a/366004)

# Features

* [x] Autodetect Barcode Scanner devices on the fly
* [x] Request Server information via [REST API](#rest-api)
* [x] Subscribe to barcode events using
    * [x] [Websocket API](#websocket-api)
* [x] Push barcode events using
    * [x] [HTTP requests](#http-request)
    * [x] [MQTT messages](#mqtt-publish)
* [x] Get [statistics](#statistics) via Prometheus exporter

# How to use

## Device Access Permissions

Ensure the user running this application is in the correct group for accessing
input devices (usually `input`), like this:

```
sudo usermod -a -G input myusername
```

## Configuration

**barcode-server** uses [container-app-conf](https://github.com/markusressel/container-app-conf)
to provide configuration via a YAML or TOML file as well as ENV variables. Have a look at the
[documentation about it](https://github.com/markusressel/container-app-conf).

The config file is searched for in the following locations (in this order):

* `./`
* `~/.config/`
* `~/`

See [barcode_server.yaml](/barcode_server.yaml) for an example in this repo.

## Native

```shell
# create venv
python -m venv ./venv
# enter venv
source ./venv/bin/activate
# install barcode-server
pip install barcode-server
# exit venv
deactivate

# print help
./venv/bin/barcode-server -h
```

This will give you an overview of all available commands:

```shell
> ./venv/bin/barcode-server -h
Usage: barcode-server [OPTIONS] COMMAND [ARGS]...

Options:
  --version   Show the version and exit.
  -h, --help  Show this message and exit.

Commands:
  config  Print the current configuration of barcode-server
  run     Run the barcode-server
```

## Docker

The docker image will by default be launched with the `run` command, making it easier
for production deployment. When starting the docker container, make sure to pass through
input devices as well as the configuration file:

```shell
docker run -it --rm \
  --name barcode \
  --device=/dev/input \
  -v "/home/markus/.config/barcode_server.yaml:/app/barcode_server.yaml" \
  -e PUID=0 \
  -e PGID=0 \
  markusressel/barcode-server
```

**Note:** Although **barcode-server** will continuously try to detect new devices,
even when passing through `/dev/input` like shown above, new devices can not be detected
due to the way docker works. If you need to detect devices in real-time, you have to use
the native approach.

The user and group id that should be used within the container can be specified using the
`PUID` and `PGID` environment variables.

To override the default command, simply specify command arguments directly:

```shell
docker run -it --rm \
  ...
  markusressel/barcode-server --help
```

# Webserver

By default the webserver will listen to `127.0.0.1` on port `9654`.

## Authorization

When specified in the config, an API token is required to authorize clients, which must
be passed using a `X-Auth-Token` header when connecting. Since barcode-scanner doesn't rely on any
persistence, the token is specified in the configuration file and can not be changed on runtime.

## Rest API

**barcode-server** provides a simple REST API to get some basic information.
This API can **not** be used to retrieve barcode events. To do that you have to use one of
the approaches described below.

| Endpoint   | Description                               |
|------------|-------------------------------------------|
| `/devices` | A list of all currently detected devices. |

## Websocket API

In addition to the REST API **barcode-server** also exposes a websocket at `/`, which can be used
to get realtime barcode scan events.

To connect to it, you have to provide

* a `Client-ID` header with a UUID (v4)
* (optional) an empty `Drop-Event-Queue` header, to ignore events that happened between connections
* (optional) an `X-Auth-Token` header, to authorize the client

Messages received on this websocket are JSON formatted strings with the following format:

```json
{
  "id": "33cb5677-3d0b-4faf-9dc4-d19a8ee7d8a1",
  "serverId": "cash-register-1",
  "date": "2020-08-03T10:00:00+00:00",
  "device": {
    "name": "BARCODE SCANNER BARCODE SCANNER",
    "path": "/dev/input/event3",
    "vendorId": "ffff",
    "productId": "0035"
  },
  "barcode": "4250168519463"
}
```

To test the connection you can use f.ex. `websocat`:

```
> websocat - autoreconnect:ws://127.0.0.1:9654 --text --header "Client-ID:dc1f14fc-a7a6-4102-af60-2b6e0dcf744c" --header "Drop-Event-Queue:" --header "X-Auth-Token:EmUSqjXGfnQwn5wn6CpzJRZgoazMTRbMNgH7CXwkQG7Ph7stex"
{"date":"2020-12-20T19:35:04.769739","device":{"name":"BARCODE SCANNER BARCODE SCANNER","path":"/dev/input/event3","vendorId":65535,"productId":53},"barcode":"D-t38409355843o52230Lm54784"}
{"date":"2020-12-20T19:35:06.237408","device":{"name":"BARCODE SCANNER BARCODE SCANNER","path":"/dev/input/event3","vendorId":65535,"productId":53},"barcode":"4250168519463"}
```

## HTTP Request

When configured, you can let **barcode-scanner** issue a HTTP request (defaults to `POST`) when a
barcode is scanned, which provides the ability to push barcode events to a server that is unaware
of any client. The body of the request will contain the same JSON as in the websocket API example.

To do this simply add the following section to your config:

```yaml
barcode_server:
  [ ... ]
  http:
    url: "https://my.domain.com/barcode"
```

Have a look at the [example config](barcode_server.yaml) for more options.

## MQTT Publish

When configured, you can let **barcode-scanner** publish barcode events to a MQTT broker.
The payload of the message will contain the same JSON as in the websocket API example.

To do this simply add the following section to your config:

```yaml
barcode_server:
  [ ... ]
  mqtt:
    host: "my.mqtt.broker"
```

Have a look at the [example config](barcode_server.yaml) for more options.

## Statistics

**barcode-server** exposes a prometheus exporter (defaults to port `8000`) to give some statistical insight.
A brief overview of (most) available metrics:

| Name                                | Type    | Description                                     |
|-------------------------------------|---------|-------------------------------------------------|
| websocket_client_count              | Gauge   | Number of currently connected websocket clients |
| devices_count                       | Gauge   | Number of currently detected devices            |
| scan_count                          | Gauge   | Number of times a scan has been detected        |
| device_detection_processing_seconds | Summary | Time spent detecting devices                    |
| rest_endpoint_processing_seconds    | Summary | Time spent in a rest command handler            |
| notifier_processing_seconds         | Summary | Time spent in a notifier                        |

# FAQ

## Can I lock the Barcode Scanner to this application?

Yes. Most barcode readers normally work like a keyboard, resulting in their input being evaluated by
the system, which can clutter up your TTY or other open programs.
**barcode-server** will try to _grab_ input devices, making it the sole recipient of all
incoming input events from those devices, which should prevent the device from cluttering
your TTY.

If, for some reason, this does not work for you, try this:

Create a file `/etc/udev/rules.d/10-barcode.rules`:

```
SUBSYSTEM=="input", ACTION=="add", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="yyyy", RUN+="/bin/sh -c 'echo remove > /sys$env{DEVPATH}/uevent'"
SUBSYSTEM=="input", ACTION=="add", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="yyyy", DEVPATH=="*:1.0/*", KERNEL=="event*", RUN+="/bin/sh -c 'ln -sf /dev/input/$kernel /dev/input/barcode_scanner'"
```

Replace the `idVendor` and `idProduct` values with the values of your barcode reader (a 4 digit hex value with leading
zeros).
You can find them in the log output of **barcode-reader** or using `lsusb` with the wireless receiver attached to your
computer.

Reload udev rules using:

```
udevadm control --reload
```

then remove and reinsert the wireless receiver.
You should now have a symlink in `/dev/input/barcode_scanner`:

```
ls -lha /dev/input/barcode_scanner
```

which can be used in the `device_paths` section of the **barcode-server** config.

Source: [This](https://serverfault.com/questions/385260/bind-usb-keyboard-exclusively-to-specific-application/976557#976557)
and [That](https://stackoverflow.com/questions/63478999/how-to-make-linux-ignore-a-keyboard-while-keeping-it-available-for-my-program-to/63531743#63531743)

# Contributing

GitHub is for social coding: if you want to write code, I encourage contributions
through pull requests from forks of this repository. Create GitHub tickets for
bugs and new features and comment on the ones that you are interested in.

# License

```text
barcode-server is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
```


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/markusressel/barcode-server",
    "name": "barcode-server",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10,<4.0",
    "maintainer_email": "",
    "keywords": "barcode,asyncio,qrcode,http,mqtt,server,websocket,websocket",
    "author": "Markus Ressel",
    "author_email": "mail@markusressel.de",
    "download_url": "https://files.pythonhosted.org/packages/00/65/e417a63879bb40a809fce1d6619d3467d7f4bf8edcfa8673261845aac7c5/barcode_server-2.4.0.tar.gz",
    "platform": null,
    "description": "# barcode-server [![Code Climate](https://codeclimate.com/github/markusressel/barcode-server.svg)](https://codeclimate.com/github/markusressel/barcode-server)\n\nA simple daemon to read barcodes from USB Barcode Scanners\nand expose them to other service using HTTP calls, a websocket API or MQTT.\n\n[![asciicast](https://asciinema.org/a/366004.svg)](https://asciinema.org/a/366004)\n\n# Features\n\n* [x] Autodetect Barcode Scanner devices on the fly\n* [x] Request Server information via [REST API](#rest-api)\n* [x] Subscribe to barcode events using\n    * [x] [Websocket API](#websocket-api)\n* [x] Push barcode events using\n    * [x] [HTTP requests](#http-request)\n    * [x] [MQTT messages](#mqtt-publish)\n* [x] Get [statistics](#statistics) via Prometheus exporter\n\n# How to use\n\n## Device Access Permissions\n\nEnsure the user running this application is in the correct group for accessing\ninput devices (usually `input`), like this:\n\n```\nsudo usermod -a -G input myusername\n```\n\n## Configuration\n\n**barcode-server** uses [container-app-conf](https://github.com/markusressel/container-app-conf)\nto provide configuration via a YAML or TOML file as well as ENV variables. Have a look at the\n[documentation about it](https://github.com/markusressel/container-app-conf).\n\nThe config file is searched for in the following locations (in this order):\n\n* `./`\n* `~/.config/`\n* `~/`\n\nSee [barcode_server.yaml](/barcode_server.yaml) for an example in this repo.\n\n## Native\n\n```shell\n# create venv\npython -m venv ./venv\n# enter venv\nsource ./venv/bin/activate\n# install barcode-server\npip install barcode-server\n# exit venv\ndeactivate\n\n# print help\n./venv/bin/barcode-server -h\n```\n\nThis will give you an overview of all available commands:\n\n```shell\n> ./venv/bin/barcode-server -h\nUsage: barcode-server [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n  --version   Show the version and exit.\n  -h, --help  Show this message and exit.\n\nCommands:\n  config  Print the current configuration of barcode-server\n  run     Run the barcode-server\n```\n\n## Docker\n\nThe docker image will by default be launched with the `run` command, making it easier\nfor production deployment. When starting the docker container, make sure to pass through\ninput devices as well as the configuration file:\n\n```shell\ndocker run -it --rm \\\n  --name barcode \\\n  --device=/dev/input \\\n  -v \"/home/markus/.config/barcode_server.yaml:/app/barcode_server.yaml\" \\\n  -e PUID=0 \\\n  -e PGID=0 \\\n  markusressel/barcode-server\n```\n\n**Note:** Although **barcode-server** will continuously try to detect new devices,\neven when passing through `/dev/input` like shown above, new devices can not be detected\ndue to the way docker works. If you need to detect devices in real-time, you have to use\nthe native approach.\n\nThe user and group id that should be used within the container can be specified using the\n`PUID` and `PGID` environment variables.\n\nTo override the default command, simply specify command arguments directly:\n\n```shell\ndocker run -it --rm \\\n  ...\n  markusressel/barcode-server --help\n```\n\n# Webserver\n\nBy default the webserver will listen to `127.0.0.1` on port `9654`.\n\n## Authorization\n\nWhen specified in the config, an API token is required to authorize clients, which must\nbe passed using a `X-Auth-Token` header when connecting. Since barcode-scanner doesn't rely on any\npersistence, the token is specified in the configuration file and can not be changed on runtime.\n\n## Rest API\n\n**barcode-server** provides a simple REST API to get some basic information.\nThis API can **not** be used to retrieve barcode events. To do that you have to use one of\nthe approaches described below.\n\n| Endpoint   | Description                               |\n|------------|-------------------------------------------|\n| `/devices` | A list of all currently detected devices. |\n\n## Websocket API\n\nIn addition to the REST API **barcode-server** also exposes a websocket at `/`, which can be used\nto get realtime barcode scan events.\n\nTo connect to it, you have to provide\n\n* a `Client-ID` header with a UUID (v4)\n* (optional) an empty `Drop-Event-Queue` header, to ignore events that happened between connections\n* (optional) an `X-Auth-Token` header, to authorize the client\n\nMessages received on this websocket are JSON formatted strings with the following format:\n\n```json\n{\n  \"id\": \"33cb5677-3d0b-4faf-9dc4-d19a8ee7d8a1\",\n  \"serverId\": \"cash-register-1\",\n  \"date\": \"2020-08-03T10:00:00+00:00\",\n  \"device\": {\n    \"name\": \"BARCODE SCANNER BARCODE SCANNER\",\n    \"path\": \"/dev/input/event3\",\n    \"vendorId\": \"ffff\",\n    \"productId\": \"0035\"\n  },\n  \"barcode\": \"4250168519463\"\n}\n```\n\nTo test the connection you can use f.ex. `websocat`:\n\n```\n> websocat - autoreconnect:ws://127.0.0.1:9654 --text --header \"Client-ID:dc1f14fc-a7a6-4102-af60-2b6e0dcf744c\" --header \"Drop-Event-Queue:\" --header \"X-Auth-Token:EmUSqjXGfnQwn5wn6CpzJRZgoazMTRbMNgH7CXwkQG7Ph7stex\"\n{\"date\":\"2020-12-20T19:35:04.769739\",\"device\":{\"name\":\"BARCODE SCANNER BARCODE SCANNER\",\"path\":\"/dev/input/event3\",\"vendorId\":65535,\"productId\":53},\"barcode\":\"D-t38409355843o52230Lm54784\"}\n{\"date\":\"2020-12-20T19:35:06.237408\",\"device\":{\"name\":\"BARCODE SCANNER BARCODE SCANNER\",\"path\":\"/dev/input/event3\",\"vendorId\":65535,\"productId\":53},\"barcode\":\"4250168519463\"}\n```\n\n## HTTP Request\n\nWhen configured, you can let **barcode-scanner** issue a HTTP request (defaults to `POST`) when a\nbarcode is scanned, which provides the ability to push barcode events to a server that is unaware\nof any client. The body of the request will contain the same JSON as in the websocket API example.\n\nTo do this simply add the following section to your config:\n\n```yaml\nbarcode_server:\n  [ ... ]\n  http:\n    url: \"https://my.domain.com/barcode\"\n```\n\nHave a look at the [example config](barcode_server.yaml) for more options.\n\n## MQTT Publish\n\nWhen configured, you can let **barcode-scanner** publish barcode events to a MQTT broker.\nThe payload of the message will contain the same JSON as in the websocket API example.\n\nTo do this simply add the following section to your config:\n\n```yaml\nbarcode_server:\n  [ ... ]\n  mqtt:\n    host: \"my.mqtt.broker\"\n```\n\nHave a look at the [example config](barcode_server.yaml) for more options.\n\n## Statistics\n\n**barcode-server** exposes a prometheus exporter (defaults to port `8000`) to give some statistical insight.\nA brief overview of (most) available metrics:\n\n| Name                                | Type    | Description                                     |\n|-------------------------------------|---------|-------------------------------------------------|\n| websocket_client_count              | Gauge   | Number of currently connected websocket clients |\n| devices_count                       | Gauge   | Number of currently detected devices            |\n| scan_count                          | Gauge   | Number of times a scan has been detected        |\n| device_detection_processing_seconds | Summary | Time spent detecting devices                    |\n| rest_endpoint_processing_seconds    | Summary | Time spent in a rest command handler            |\n| notifier_processing_seconds         | Summary | Time spent in a notifier                        |\n\n# FAQ\n\n## Can I lock the Barcode Scanner to this application?\n\nYes. Most barcode readers normally work like a keyboard, resulting in their input being evaluated by\nthe system, which can clutter up your TTY or other open programs.\n**barcode-server** will try to _grab_ input devices, making it the sole recipient of all\nincoming input events from those devices, which should prevent the device from cluttering\nyour TTY.\n\nIf, for some reason, this does not work for you, try this:\n\nCreate a file `/etc/udev/rules.d/10-barcode.rules`:\n\n```\nSUBSYSTEM==\"input\", ACTION==\"add\", ATTRS{idVendor}==\"xxxx\", ATTRS{idProduct}==\"yyyy\", RUN+=\"/bin/sh -c 'echo remove > /sys$env{DEVPATH}/uevent'\"\nSUBSYSTEM==\"input\", ACTION==\"add\", ATTRS{idVendor}==\"xxxx\", ATTRS{idProduct}==\"yyyy\", DEVPATH==\"*:1.0/*\", KERNEL==\"event*\", RUN+=\"/bin/sh -c 'ln -sf /dev/input/$kernel /dev/input/barcode_scanner'\"\n```\n\nReplace the `idVendor` and `idProduct` values with the values of your barcode reader (a 4 digit hex value with leading\nzeros).\nYou can find them in the log output of **barcode-reader** or using `lsusb` with the wireless receiver attached to your\ncomputer.\n\nReload udev rules using:\n\n```\nudevadm control --reload\n```\n\nthen remove and reinsert the wireless receiver.\nYou should now have a symlink in `/dev/input/barcode_scanner`:\n\n```\nls -lha /dev/input/barcode_scanner\n```\n\nwhich can be used in the `device_paths` section of the **barcode-server** config.\n\nSource: [This](https://serverfault.com/questions/385260/bind-usb-keyboard-exclusively-to-specific-application/976557#976557)\nand [That](https://stackoverflow.com/questions/63478999/how-to-make-linux-ignore-a-keyboard-while-keeping-it-available-for-my-program-to/63531743#63531743)\n\n# Contributing\n\nGitHub is for social coding: if you want to write code, I encourage contributions\nthrough pull requests from forks of this repository. Create GitHub tickets for\nbugs and new features and comment on the ones that you are interested in.\n\n# License\n\n```text\nbarcode-server is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <https://www.gnu.org/licenses/>.\n```\n\n",
    "bugtrack_url": null,
    "license": "AGPL-3.0-or-later",
    "summary": "A simple daemon to expose USB Barcode Scanner data to other services using Websockets, Webhooks or MQTT.",
    "version": "2.4.0",
    "project_urls": {
        "Homepage": "https://github.com/markusressel/barcode-server",
        "Repository": "https://github.com/markusressel/barcode-server"
    },
    "split_keywords": [
        "barcode",
        "asyncio",
        "qrcode",
        "http",
        "mqtt",
        "server",
        "websocket",
        "websocket"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c21fe587dc1fa356d9067576e7e1ce44a9eadccf67d5ed6f1de15e258cce7095",
                "md5": "da147027b8919197324ec8a12ac42c81",
                "sha256": "0d76a4deedd0a4065c1fb56e78d39002e6d034c36d868c8306fed485509f9043"
            },
            "downloads": -1,
            "filename": "barcode_server-2.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "da147027b8919197324ec8a12ac42c81",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10,<4.0",
            "size": 31390,
            "upload_time": "2023-09-09T13:49:36",
            "upload_time_iso_8601": "2023-09-09T13:49:36.382395Z",
            "url": "https://files.pythonhosted.org/packages/c2/1f/e587dc1fa356d9067576e7e1ce44a9eadccf67d5ed6f1de15e258cce7095/barcode_server-2.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0065e417a63879bb40a809fce1d6619d3467d7f4bf8edcfa8673261845aac7c5",
                "md5": "22159bf85b5057b299fa22b3788618f8",
                "sha256": "e2c84511d37275f3ec9341889f74e39281fb651a61b1d03f61117f28e110348a"
            },
            "downloads": -1,
            "filename": "barcode_server-2.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "22159bf85b5057b299fa22b3788618f8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10,<4.0",
            "size": 29600,
            "upload_time": "2023-09-09T13:49:38",
            "upload_time_iso_8601": "2023-09-09T13:49:38.117356Z",
            "url": "https://files.pythonhosted.org/packages/00/65/e417a63879bb40a809fce1d6619d3467d7f4bf8edcfa8673261845aac7c5/barcode_server-2.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-09-09 13:49:38",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "markusressel",
    "github_project": "barcode-server",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "barcode-server"
}
        
Elapsed time: 0.14049s