Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to Setuptools Python Packaging #13

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
__pycache__
*~

build/
.eggs/
eggs/
*.egg-info/
*.egg
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ Copyright (C) 2023 Vladimir Vukicevic

## Usage

Python 3 is required. Use `pip install -r requirements.txt` to install dependencies.
Python 3 is required.

Clone and install via pip: `pip install .`

Install directly from git via pipx: `pipx install git+https://github.com/vvuk/cassini.git`

### Printer status

```
$ ./cassini.py status
$ cassini status
192.168.7.128: Saturn3Ultra (ELEGOO Saturn 3 Ultra) Status: 1
Print Status: 2 Layers: 19/130
File Transfer Status: 0
Expand All @@ -30,7 +34,7 @@ $ ./cassini.py status
### Printer(s) full status

```
$ ./cassini.py status-full
$ cassini status-full
```

Will print out the full json status of all printers found.
Expand All @@ -39,22 +43,22 @@ Will print out the full json status of all printers found.
### Watch live print progress

```
$ ./cassini.py watch [interval]
$ cassini watch [interval]
_STL_B_Warriors_1_Sword_Combined_Supported.goo |███████████████████████████████████▉ ︎ | 90%
```

### File transfer

```
$ ./cassini.py [--printer printer_ip] upload MyFile.goo
$ cassini [--printer printer_ip] upload MyFile.goo
15:39:15,190 INFO: Using printer Saturn3Ultra (ELEGOO Saturn 3 Ultra)
MyFile.goo |████████████████████████████████████████| 100% [5750174/5750174] (3291238.22/s)
```

### Start a print (of an existing file)

```
$ ./cassini.py [--printer printer_ip] print Myfile.goo
$ cassini [--printer printer_ip] print Myfile.goo
```

### Connect printer(s) to particular MQTT server
Expand Down Expand Up @@ -168,14 +172,14 @@ The printer subscribes to a request topic specific to its mainboard ID `/sdcp/re

Commands discovered:

| ID | Description | Data |
|-----|-------------|------|
| 0 | Unknown. Sent by CHITUBOX first. | None |
| 1 | Unknown. Sent by CHITUBOX after 0. | None |
| 64 | Maybe a disconnect? | None |
| 128 | Start printing. | See below. |
| 256 | Upload file. | See below. |
| 512 | Set some kind of time period. | `{ "TimePeriod": 5000 }` |
| ID | Description | Data |
| --- | ---------------------------------- | ------------------------ |
| 0 | Unknown. Sent by CHITUBOX first. | None |
| 1 | Unknown. Sent by CHITUBOX after 0. | None |
| 64 | Maybe a disconnect? | None |
| 128 | Start printing. | See below. |
| 256 | Upload file. | See below. |
| 512 | Set some kind of time period. | `{ "TimePeriod": 5000 }` |

#### 128: Start Printing

Expand Down
Empty file added cassini/__init__.py
Empty file.
119 changes: 81 additions & 38 deletions cassini.py → cassini/cassini.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
import asyncio
import logging
import argparse
from simple_mqtt_server import SimpleMQTTServer
from simple_http_server import SimpleHTTPServer
from saturn_printer import SaturnPrinter, PrintInfoStatus, CurrentStatus, FileStatus
from .simple_mqtt_server import SimpleMQTTServer
from .simple_http_server import SimpleHTTPServer
from .saturn_printer import SaturnPrinter, PrintInfoStatus, CurrentStatus, FileStatus

logging.basicConfig(
level=logging.INFO,
Expand All @@ -28,35 +28,42 @@
from alive_progress import alive_bar
except ImportError:
logging.info("Run 'pip3 install alive-progress' for better progress bars")

class alive_bar(object):
def __init__(self, total, title, **kwargs):
self.total = total
self.title = title

def __call__(self, x):
print(f"{int(x*self.total)}/{self.total} {self.title}\r", end="")

def __enter__(self):
return self

def __exit__(self, *args):
print("\n")


async def create_mqtt_server():
mqtt = SimpleMQTTServer('0.0.0.0', 0)
mqtt = SimpleMQTTServer("0.0.0.0", 0)
await mqtt.start()
mqtt_server_task = asyncio.create_task(mqtt.serve_forever())
return mqtt, mqtt.port, mqtt_server_task


async def create_http_server():
http = SimpleHTTPServer('0.0.0.0', 0)
http = SimpleHTTPServer("0.0.0.0", 0)
await http.start()
http_server_task = asyncio.create_task(http.serve_forever())
return http, http.port, http_server_task


def do_status(printers):
for i, p in enumerate(printers):
attrs = p.desc['Data']['Attributes']
status = p.desc['Data']['Status']
print_info = status['PrintInfo']
file_info = status['FileTransferInfo']
attrs = p.desc["Data"]["Attributes"]
status = p.desc["Data"]["Status"]
print_info = status["PrintInfo"]
file_info = status["FileTransferInfo"]
print(f"{p.addr[0]}:")
print(f" {attrs['Name']} ({attrs['MachineName']})")
print(f" Machine Status: {CurrentStatus(status['CurrentStatus']).name}")
Expand All @@ -65,30 +72,38 @@ def do_status(printers):
print(f" File: {print_info['Filename']}")
print(f" File Transfer Status: {FileStatus(file_info['Status']).name}")


def do_status_full(printers):
for i, p in enumerate(printers):
pprint.pprint(p.desc)


def do_watch(printer, interval=5, broadcast=None):
status = printer.status()
with alive_bar(total=status['totalLayers'], manual=True, elapsed=False, title=status['filename']) as bar:
with alive_bar(
total=status["totalLayers"],
manual=True,
elapsed=False,
title=status["filename"],
) as bar:
while True:
printers = SaturnPrinter.find_printers(broadcast=broadcast)
if len(printers) > 0:
status = printers[0].status()
pct = status['currentLayer'] / status['totalLayers']
pct = status["currentLayer"] / status["totalLayers"]
bar(pct)
if pct >= 1.0:
break
time.sleep(interval)


async def create_servers():
mqtt, mqtt_port, mqtt_task = await create_mqtt_server()
http, http_port, http_task = await create_http_server()

return mqtt, http


async def do_print(printer, filename):
mqtt, http = await create_servers()
connected = await printer.connect(mqtt, http)
Expand All @@ -103,6 +118,7 @@ async def do_print(printer, filename):
logging.error("Failed to start print")
sys.exit(1)


async def do_upload(printer, filename, start_printing=False):
if not os.path.exists(filename):
logging.error(f"{filename} does not exist")
Expand All @@ -113,11 +129,13 @@ async def do_upload(printer, filename, start_printing=False):
if not connected:
logging.error("Failed to connect to printer")
sys.exit(1)

#await printer.upload_file(filename, start_printing=start_printing)
upload_task = asyncio.create_task(printer.upload_file(filename, start_printing=start_printing))

# await printer.upload_file(filename, start_printing=start_printing)
upload_task = asyncio.create_task(
printer.upload_file(filename, start_printing=start_printing)
)
# grab the first one, because we want the file size
basename = filename.split('\\')[-1].split('/')[-1]
basename = filename.split("\\")[-1].split("/")[-1]
file_size = os.path.getsize(filename)
with alive_bar(total=file_size, manual=True, elapsed=False, title=basename) as bar:
while True:
Expand All @@ -133,29 +151,51 @@ async def do_upload(printer, filename, start_printing=False):
break
await upload_task


def main():
parser = argparse.ArgumentParser(prog='cassini', description='ELEGOO Saturn printer control utility')
parser.add_argument('-p', '--printer', help='ID of printer to target')
parser.add_argument('--broadcast', help='Explicit broadcast IP address')
parser.add_argument('--debug', help='Enable debug logging', action='store_true')
parser = argparse.ArgumentParser(
prog="cassini", description="ELEGOO Saturn printer control utility"
)
parser.add_argument("-p", "--printer", help="ID of printer to target")
parser.add_argument("--broadcast", help="Explicit broadcast IP address")
parser.add_argument("--debug", help="Enable debug logging", action="store_true")

subparsers = parser.add_subparsers(title="commands", dest="command", required=True)

parser_status = subparsers.add_parser('status', help='Discover and display status of all printers')
parser_status_full = subparsers.add_parser('status-full', help='Discover and display full status of all printers')

parser_watch = subparsers.add_parser('watch', help='Continuously update the status of the selected printer')
parser_watch.add_argument('--interval', type=int, help='Status update interval (seconds)', default=5)

parser_upload = subparsers.add_parser('upload', help='Upload a file to the printer')
parser_upload.add_argument('--start-printing', help='Start printing after upload is complete', action='store_true')
parser_upload.add_argument('filename', help='File to upload')

parser_print = subparsers.add_parser('print', help='Start printing a file already present on the printer')
parser_print.add_argument('filename', help='File to print')

parser_connect_mqtt = subparsers.add_parser('connect-mqtt', help='Connect printer to particular MQTT server')
parser_connect_mqtt.add_argument('address', help='MQTT host and port, e.g. "192.168.1.33:1883" or "mqtt.local:1883"')
parser_status = subparsers.add_parser(
"status", help="Discover and display status of all printers"
)
parser_status_full = subparsers.add_parser(
"status-full", help="Discover and display full status of all printers"
)

parser_watch = subparsers.add_parser(
"watch", help="Continuously update the status of the selected printer"
)
parser_watch.add_argument(
"--interval", type=int, help="Status update interval (seconds)", default=5
)

parser_upload = subparsers.add_parser("upload", help="Upload a file to the printer")
parser_upload.add_argument(
"--start-printing",
help="Start printing after upload is complete",
action="store_true",
)
parser_upload.add_argument("filename", help="File to upload")

parser_print = subparsers.add_parser(
"print", help="Start printing a file already present on the printer"
)
parser_print.add_argument("filename", help="File to print")

parser_connect_mqtt = subparsers.add_parser(
"connect-mqtt", help="Connect printer to particular MQTT server"
)
parser_connect_mqtt.add_argument(
"address",
help='MQTT host and port, e.g. "192.168.1.33:1883" or "mqtt.local:1883"',
)

args = parser.parse_args()

Expand Down Expand Up @@ -187,7 +227,7 @@ def main():
sys.exit(0)

if args.command == "connect-mqtt":
mqtt_host, mqtt_port = args.address.split(':')
mqtt_host, mqtt_port = args.address.split(":")
try:
mqtt_host = socket.gethostbyname(mqtt_host)
except socket.gaierror:
Expand All @@ -199,14 +239,17 @@ def main():
do_watch(printer, interval=args.interval, broadcast=broadcast)
sys.exit(0)

logging.info(f'Printer: {printer.describe()} ({printer.addr[0]})')
logging.info(f"Printer: {printer.describe()} ({printer.addr[0]})")
if printer.busy:
logging.error(f'Printer is busy (status: {printer.current_status})')
logging.error(f"Printer is busy (status: {printer.current_status})")
sys.exit(1)

if args.command == "upload":
asyncio.run(do_upload(printer, args.filename, start_printing=args.start_printing))
asyncio.run(
do_upload(printer, args.filename, start_printing=args.start_printing)
)
elif args.command == "print":
asyncio.run(do_print(printer, args.filename))


main()
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 0 additions & 2 deletions requirements.txt

This file was deleted.

12 changes: 12 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from setuptools import setup, find_packages

setup(
name="cassini",
version="0.0.1",
install_requires=[
"alive-progress==3.1.4",
"scapy==2.5.0",
],
packages=find_packages(),
entry_points={"console_scripts": ["cassini = cassini.cassini:main"]},
)