link-sync


Namelink-sync JSON
Version 0.2.5 PyPI version JSON
download
home_pagehttps://github.com/mkoistinen/link-sync
SummarySynchronize GCode files across your printer farm.
upload_time2023-10-24 23:35:49
maintainer
docs_urlNone
authorMartin Koistinen
requires_python>=3.10
licenseApache-2.0
keywords prusalink prusa-link
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # Link Sync

## Purpose

The goal of this project is to sync gcode files from a local "master" directory
to any number of Prusa printers on the local network running PrusaLink when
they are idle, simultaneously.

Transfering files is tediously slow, so the idea is to sync several printers
all at once. This is a powerful workflow for farm operators who may have a
new model that replaces an older one and negates the need to send it
individually to every printer, or, to manually fetch their USB stick/other
to for updating at your local machine.

Also, by removing files that aren't in the local "master" directory, once off
prints are automatically cleaned up from a printer's USB stick.


## Theory of Operation

Locally, a "master" file structure is maintained containing all the GCode files
required at the target machines. Also, configuration file in either YAML or
JSON format is kept on the local machine that contains the connection details
for each printer.

The program reads the configuration file, instantiates printer instances, then
for the printers that aren't currently busy, a thread is spawned which is
responsible for check what files should be deleted from the printer, or copied
to the printer to bring it into sync with the local "master" file-structure.

These threads then operate simultaneously to bring all idle printers into sync
at roughly the same time.

Note that PrusaLink running on the printer refuses to delete a file that is
actively being printed. This is a good thing.

Being a command-line program, it would be easy to set up with `cron` to run
every hour on the hour from 7pm to 7am (overnight) to ensure that all printers
get synced/cleaned up from the previous day's run and ready to go for the
next day.


## Currently Implemented Features

Printers currently supported:

- [x] Prusa MK4 running firmware 5.0.0 RC1 and later.

TODO:

- [ ] Prusa XL
- [ ] Prusa Mini
- [ ] Prusa MK3


Features:

- [x] Add new files that were found in local source but not in remote storage.
- [x] Delete excess files not found in local source but are in remote storage.
- [x] Optionally operate on printers that are not idle.
- [x] Replace stale files that have a modification date more recent (> 60 sec.)
      than the same file on the remote storage.

TODO:

- [ ] Optionally, copy files that exist on a printer that are unique back to
      the local filesystem.

## Example usage

### Scenario

The author maintains a set of files on his local workstation's filesystem at:

    ~/master_farm_files/usb

Within this directory, he adds all his GCode organized into directories, if
he so desires. He knows that PrusaLink has limits on how long filepaths can be
on the printer, so he keeps the directories shallow and with reasonably short
names. For example a directory structure like this:

    ~/master_farm_files/usb/
        apple/
            prusament pla/
                apple_0.4n_0.15mm_PLA_MK4IS_4h52m.gcode
            prusament petg/
                apple_0.4n_0.15mm_PETG_MK4IS_4h58m.gcode
        banana/
            prusament pla/
                banana_0.4n_0.15mm_PLA_MK4IS_2h12m.gcode
            prusament petg/
                banana_0.4n_0.15mm_PETG_MK4IS_2h13m.gcode

The author has a bank of 4 Original Prusa MK4 printers. He creates a
configuration file `~/printers.yml` somewhere that contains their details
as follows:

``` yml
Ash:
    printer_type: MK4
    host: http://192.168.0.1
    username: maker
    password: password1
Bishop:
    printer_type: MK4
    host: http://192.168.0.2
    username: maker
    password: password2
Call:
    printer_type: MK4
    host: http://192.168.0.3
    username: maker
    password: password3
David:
    printer_type: MK4
    host: http://192.168.0.4
    username: maker
    password: password4
```

Then, the author creates a virtual Python environment and installs `link-sync`.

    ❯ pip install link-sync

This Python package installs a command line utility called `link-sync` which
can be used like so:

    ❯ link-sync --config ~/printers.yml --source ~/master_farm_files/usb --destination /usb/

The program will show a preview of what *would* happen if the `--go` option was provided.

If the operations look correct, rerun the program with the `--go` argument:

    ❯ link-sync --config ~/printers.yml --source ~/master_farm_files/usb --destination /usb/ --go

And the files will be copied across all printers at the same time.

Many of the arguments can be abbreviated. For example the above line could be:

    ❯ link-sync -c ~/printers.yml -s ~/master_farm_files/usb -d /usb/ -g

Note the short version of `--go` is `-g`.

You can use the built-in help function to see other options:

```
❯ link-sync --help
usage: link_sync [-h] [-c CONFIG_PATH] [-p [INCLUDED_PRINTERS ...]]
                 [-x [EXCLUDED_PRINTERS ...]] -s SOURCE_PATH
                 [-d DESTINATION_PATH] [-r RELATIVE_TO_PATH] [-g]
                 [--ignore-state]

options:
  -h, --help            show this help message and exit
  -c CONFIG_PATH, --config CONFIG_PATH
                        Path to a YAML or JSON file containing the
                        configuration of all printers. Default is
                        `printers.yml` in the current working directory.
  -p [INCLUDED_PRINTERS ...], --printer [INCLUDED_PRINTERS ...]
                        Explicitly name printers to INCLUDE for processing. By
                        default, all idle (see the `--ignore-state` option)
                        printers found in the will configuration be processed.
  -x [EXCLUDED_PRINTERS ...], --exclude [EXCLUDED_PRINTERS ...]
                        Explicitly name printers to EXCLUDE from processing.
                        By default, all idle (see the `--ignore-state option)
                        printers found in the configuration will be processed.
                        This option will be ignored if the `--printer` option
                        is used.
  -s SOURCE_PATH, --source SOURCE_PATH
                        The local path to the root of the files that should be
                        synced.
  -d DESTINATION_PATH, --destination DESTINATION_PATH
                        The relative path within the printers' storage where
                        the source files should be synchronized. Default is
                        the root of the printers' storage.
  -r RELATIVE_TO_PATH, --relative-to RELATIVE_TO_PATH
                        If provided, the SOURCE_PATH file paths will consider
                        only the portion of the path that is relative to this
                        given path. If not provided, it is set to the
                        SOURCE_PATH itself.
  -g, --go              Make the changes (do not do a dry-run).
  --ignore-state        If set, all printers, including busy printers, will be
                        processed. Use with caution as some printers may
                        experience print failures when printing and API calls
                        are received and processed.
```


Copyright (c) 2023, Martin Koistinen

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/mkoistinen/link-sync",
    "name": "link-sync",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": "",
    "keywords": "prusalink,prusa-link",
    "author": "Martin Koistinen",
    "author_email": "mkoistinen@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/b3/d5/81f4462e546b90d2210b001bb14ee35edf52b96c97e1f3d627b461146724/link-sync-0.2.5.tar.gz",
    "platform": null,
    "description": "# Link Sync\n\n## Purpose\n\nThe goal of this project is to sync gcode files from a local \"master\" directory\nto any number of Prusa printers on the local network running PrusaLink when\nthey are idle, simultaneously.\n\nTransfering files is tediously slow, so the idea is to sync several printers\nall at once. This is a powerful workflow for farm operators who may have a\nnew model that replaces an older one and negates the need to send it\nindividually to every printer, or, to manually fetch their USB stick/other\nto for updating at your local machine.\n\nAlso, by removing files that aren't in the local \"master\" directory, once off\nprints are automatically cleaned up from a printer's USB stick.\n\n\n## Theory of Operation\n\nLocally, a \"master\" file structure is maintained containing all the GCode files\nrequired at the target machines. Also, configuration file in either YAML or\nJSON format is kept on the local machine that contains the connection details\nfor each printer.\n\nThe program reads the configuration file, instantiates printer instances, then\nfor the printers that aren't currently busy, a thread is spawned which is\nresponsible for check what files should be deleted from the printer, or copied\nto the printer to bring it into sync with the local \"master\" file-structure.\n\nThese threads then operate simultaneously to bring all idle printers into sync\nat roughly the same time.\n\nNote that PrusaLink running on the printer refuses to delete a file that is\nactively being printed. This is a good thing.\n\nBeing a command-line program, it would be easy to set up with `cron` to run\nevery hour on the hour from 7pm to 7am (overnight) to ensure that all printers\nget synced/cleaned up from the previous day's run and ready to go for the\nnext day.\n\n\n## Currently Implemented Features\n\nPrinters currently supported:\n\n- [x] Prusa MK4 running firmware 5.0.0 RC1 and later.\n\nTODO:\n\n- [ ] Prusa XL\n- [ ] Prusa Mini\n- [ ] Prusa MK3\n\n\nFeatures:\n\n- [x] Add new files that were found in local source but not in remote storage.\n- [x] Delete excess files not found in local source but are in remote storage.\n- [x] Optionally operate on printers that are not idle.\n- [x] Replace stale files that have a modification date more recent (> 60 sec.)\n      than the same file on the remote storage.\n\nTODO:\n\n- [ ] Optionally, copy files that exist on a printer that are unique back to\n      the local filesystem.\n\n## Example usage\n\n### Scenario\n\nThe author maintains a set of files on his local workstation's filesystem at:\n\n    ~/master_farm_files/usb\n\nWithin this directory, he adds all his GCode organized into directories, if\nhe so desires. He knows that PrusaLink has limits on how long filepaths can be\non the printer, so he keeps the directories shallow and with reasonably short\nnames. For example a directory structure like this:\n\n    ~/master_farm_files/usb/\n        apple/\n            prusament pla/\n                apple_0.4n_0.15mm_PLA_MK4IS_4h52m.gcode\n            prusament petg/\n                apple_0.4n_0.15mm_PETG_MK4IS_4h58m.gcode\n        banana/\n            prusament pla/\n                banana_0.4n_0.15mm_PLA_MK4IS_2h12m.gcode\n            prusament petg/\n                banana_0.4n_0.15mm_PETG_MK4IS_2h13m.gcode\n\nThe author has a bank of 4 Original Prusa MK4 printers. He creates a\nconfiguration file `~/printers.yml` somewhere that contains their details\nas follows:\n\n``` yml\nAsh:\n    printer_type: MK4\n    host: http://192.168.0.1\n    username: maker\n    password: password1\nBishop:\n    printer_type: MK4\n    host: http://192.168.0.2\n    username: maker\n    password: password2\nCall:\n    printer_type: MK4\n    host: http://192.168.0.3\n    username: maker\n    password: password3\nDavid:\n    printer_type: MK4\n    host: http://192.168.0.4\n    username: maker\n    password: password4\n```\n\nThen, the author creates a virtual Python environment and installs `link-sync`.\n\n    \u276f pip install link-sync\n\nThis Python package installs a command line utility called `link-sync` which\ncan be used like so:\n\n    \u276f link-sync --config ~/printers.yml --source ~/master_farm_files/usb --destination /usb/\n\nThe program will show a preview of what *would* happen if the `--go` option was provided.\n\nIf the operations look correct, rerun the program with the `--go` argument:\n\n    \u276f link-sync --config ~/printers.yml --source ~/master_farm_files/usb --destination /usb/ --go\n\nAnd the files will be copied across all printers at the same time.\n\nMany of the arguments can be abbreviated. For example the above line could be:\n\n    \u276f link-sync -c ~/printers.yml -s ~/master_farm_files/usb -d /usb/ -g\n\nNote the short version of `--go` is `-g`.\n\nYou can use the built-in help function to see other options:\n\n```\n\u276f link-sync --help\nusage: link_sync [-h] [-c CONFIG_PATH] [-p [INCLUDED_PRINTERS ...]]\n                 [-x [EXCLUDED_PRINTERS ...]] -s SOURCE_PATH\n                 [-d DESTINATION_PATH] [-r RELATIVE_TO_PATH] [-g]\n                 [--ignore-state]\n\noptions:\n  -h, --help            show this help message and exit\n  -c CONFIG_PATH, --config CONFIG_PATH\n                        Path to a YAML or JSON file containing the\n                        configuration of all printers. Default is\n                        `printers.yml` in the current working directory.\n  -p [INCLUDED_PRINTERS ...], --printer [INCLUDED_PRINTERS ...]\n                        Explicitly name printers to INCLUDE for processing. By\n                        default, all idle (see the `--ignore-state` option)\n                        printers found in the will configuration be processed.\n  -x [EXCLUDED_PRINTERS ...], --exclude [EXCLUDED_PRINTERS ...]\n                        Explicitly name printers to EXCLUDE from processing.\n                        By default, all idle (see the `--ignore-state option)\n                        printers found in the configuration will be processed.\n                        This option will be ignored if the `--printer` option\n                        is used.\n  -s SOURCE_PATH, --source SOURCE_PATH\n                        The local path to the root of the files that should be\n                        synced.\n  -d DESTINATION_PATH, --destination DESTINATION_PATH\n                        The relative path within the printers' storage where\n                        the source files should be synchronized. Default is\n                        the root of the printers' storage.\n  -r RELATIVE_TO_PATH, --relative-to RELATIVE_TO_PATH\n                        If provided, the SOURCE_PATH file paths will consider\n                        only the portion of the path that is relative to this\n                        given path. If not provided, it is set to the\n                        SOURCE_PATH itself.\n  -g, --go              Make the changes (do not do a dry-run).\n  --ignore-state        If set, all printers, including busy printers, will be\n                        processed. Use with caution as some printers may\n                        experience print failures when printing and API calls\n                        are received and processed.\n```\n\n\nCopyright (c) 2023, Martin Koistinen\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Synchronize GCode files across your printer farm.",
    "version": "0.2.5",
    "project_urls": {
        "Homepage": "https://github.com/mkoistinen/link-sync"
    },
    "split_keywords": [
        "prusalink",
        "prusa-link"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "19377e96c8f6dd06647a5267e53fcc47148599043688a7fd14ba27a6f208987a",
                "md5": "9003952bb513a9defdecc97580d48c87",
                "sha256": "4f0d16f8d0251492dba9762641d445c9d138f206b744119cd3f4aaa47e778485"
            },
            "downloads": -1,
            "filename": "link_sync-0.2.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9003952bb513a9defdecc97580d48c87",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 18796,
            "upload_time": "2023-10-24T23:35:45",
            "upload_time_iso_8601": "2023-10-24T23:35:45.925746Z",
            "url": "https://files.pythonhosted.org/packages/19/37/7e96c8f6dd06647a5267e53fcc47148599043688a7fd14ba27a6f208987a/link_sync-0.2.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b3d581f4462e546b90d2210b001bb14ee35edf52b96c97e1f3d627b461146724",
                "md5": "b01c870fb9a8048a3d49acdf28328dcd",
                "sha256": "67e249304e5b0717d3c99ceabd404ae4db27891d5631d1d378721a815ea6b14f"
            },
            "downloads": -1,
            "filename": "link-sync-0.2.5.tar.gz",
            "has_sig": false,
            "md5_digest": "b01c870fb9a8048a3d49acdf28328dcd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 22279,
            "upload_time": "2023-10-24T23:35:49",
            "upload_time_iso_8601": "2023-10-24T23:35:49.459369Z",
            "url": "https://files.pythonhosted.org/packages/b3/d5/81f4462e546b90d2210b001bb14ee35edf52b96c97e1f3d627b461146724/link-sync-0.2.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-10-24 23:35:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mkoistinen",
    "github_project": "link-sync",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "lcname": "link-sync"
}
        
Elapsed time: 0.12863s