feat: add connect-mqtt command

This commit is contained in:
Anton Osenenko
2024-03-31 04:14:51 +02:00
parent 75f78dcb0d
commit 48907cc54b
4 changed files with 59 additions and 2 deletions

View File

@@ -16,8 +16,7 @@ Copyright (C) 2023 Vladimir Vukicevic
## Usage
Python 3 is required. There are no other requirements, but you should
install the `alive-progress` package for nicer progress bars (`pip3 install alive-progress`).
Python 3 is required. Use `pip install -r requirements.txt` to install dependencies.
### Printer status
@@ -28,6 +27,15 @@ $ ./cassini.py status
File Transfer Status: 0
```
### Printer(s) full status
```
$ ./cassini.py status-full
```
Will print out the full json status of all printers found.
### Watch live print progress
```
@@ -49,6 +57,16 @@ MyFile.goo |██████████████████████
$ ./cassini.py [--printer printer_ip] print Myfile.goo
```
### Connect printer(s) to particular MQTT server
```
$ [sudo] python cassini.py [--printer printer_ip] connect-mqtt mqtt.local:1883
```
Probably you need to use `sudo` (at least on MacOS, or you'll get `Permission denied: could not open /dev/bpf0. Make sure to be running Scapy as root`).
If `--printer` is not specified, all printers found will be connected to the same MQTT server.
## Protocol Description
The protocol is pretty simple. There is no encryption or any obfuscation that I could find.

View File

@@ -7,6 +7,8 @@
# License: MIT
#
import os
import pprint
import socket
import sys
import time
import asyncio
@@ -63,6 +65,11 @@ 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:
@@ -135,6 +142,7 @@ def main():
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)
@@ -146,6 +154,9 @@ def main():
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()
if args.debug:
@@ -171,6 +182,19 @@ def main():
do_status(printers)
sys.exit(0)
if args.command == "status-full":
do_status_full(printers)
sys.exit(0)
if args.command == "connect-mqtt":
mqtt_host, mqtt_port = args.address.split(':')
try:
mqtt_host = socket.gethostbyname(mqtt_host)
except socket.gaierror:
pass
for p in printers:
p.connect_mqtt(mqtt_host, mqtt_port)
if args.command == "watch":
do_watch(printer, interval=args.interval, broadcast=broadcast)
sys.exit(0)

View File

@@ -1 +1,2 @@
alive-progress==3.1.4
scapy==2.5.0

View File

@@ -14,6 +14,7 @@ import asyncio
import logging
import random
from enum import Enum
from scapy.all import IP, UDP, send
SATURN_UDP_PORT = 3000
@@ -320,3 +321,16 @@ class SaturnPrinter:
}
self.mqtt.publish('/sdcp/request/' + self.id, json.dumps(cmd_data))
return hexstr
def connect_mqtt(self, mqtt_host, mqtt_port):
"""
Connect printer to MQTT server
It spoofs UDP packet to the printer to make it connect to particular MQTT server
"""
ip = IP(dst=self.addr[0], src=mqtt_host)
any_src_port = random.randint(1024, 65535)
udp = UDP(sport=any_src_port, dport=SATURN_UDP_PORT)
payload = f"M66666 {mqtt_port}"
packet = ip / udp / payload
send(packet)