Code Monkey home page Code Monkey logo

andycb / adventurerclientjs Goto Github PK

View Code? Open in Web Editor NEW
37.0 5.0 12.0 2.62 MB

An unofficial cross platform client for working with the Monoprice Voxel or Flashforge Adventurer 3

Home Page: https://andybradford.dev/2020/08/26/an-app-to-transfer-files-to-the-flashforge-adventurer-or-monoprice-voxel/

License: MIT License

TypeScript 83.53% CSS 2.99% HTML 9.62% JavaScript 2.44% SCSS 1.43%
3dprinting 3dprinter 3dprint electron-app electron electronjs typescript adventurer-client flashforge-adventurer monoprice-voxel

adventurerclientjs's Introduction

AdventurerClientJS

A cross platform application for communicating with the FlashForge Adventurer and Monoprice Voxel 3D Printer.

Building

  1. Install NodeJS
  2. In a command prompt change to the src directory
  3. Run $ npm install
  4. Run $ npm run electron

Fake Printer

To simplify development and testing, a fake printer is included that will return realistic data to the client. To run it:

  1. In a command prompt change to the stubPrinter directory
  2. Run $ node stubPrinter.js
  3. In the client connect to "localhost' to use the fake printer

Errors

“Adventurer Client” cannot be opened because the developer cannot be verified.

Unfortunately, Apple require that app software running on macOS be signed and Notarized so that they can verify its identity. Doing this would require me to buy a code signing certificate and an Apple Developer license which is quite expensive. Therefore, for the time being, the app is distributed unsigned. To run the app you need to perform the following steps, for the first run only.

  1. Double click on "Adventurer Client"
  2. At the “Adventurer Client” cannot be opened because the developer cannot be verified. message, click cancel
  3. Right click on the app and click open
  4. At the macOS cannot verify the developer of “Adventurer Client”. Are you sure you want to open it? message, click Open

Running

Windows and Mac builds are available in releases. Note, the builds are not signed, so will generate an OS warning when first run.

TODO

  • ⏺ Support for more functions
  • ⏺ Support command line arguments
  • ⏺ Unit tests
  • ⏺ Sign & Notarize binaries to avoid warnings.

adventurerclientjs's People

Contributors

andycb avatar dependabot[bot] avatar gaweringo avatar veryvince avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

adventurerclientjs's Issues

CRC Error on my client when uploading

Hi, I have been looking for an sdk for the MP Voxel / FlashForge Adventurer 3 for nodejs and have found nothing decent but this. I am trying to make a server so I can print anything, anywhere. The code that I have copied and modified that for some reason, won't work. It works in your app, but not mine. The files below are the only ones used. Is there any way you could help me? Thanks!

conn.ts

import net from 'net';
import { EventEmitter } from 'events';
import codes from './codes';
import { crc32 } from 'crc';
import fs from 'fs';

class Connection extends EventEmitter {
    socket: net.Socket;
    conopt = {
        host: '',
        port: 0,
    }
    sending_gcode = false;

    constructor(host: string, port: number) {
        super();
        this.socket = new net.Socket();

        this.conopt = { host, port }

        this.socket.on('data', (data) => {
            this.emit('data', data);
            const d = this.matchData(data);
            if (d.cmd === 'M105') {
                d.data = {
                    extruder: parseInt(d.data.match(/T0:([0-9]+)/)![1]),
                    bed: parseInt(d.data.match(/B:([0-9]+)/)![1]),
                }
            }
            this.emit(d.cmd, d.data);
            this.emit(codes[d.cmd], d.data);
        });

        this.socket.on('end', () => {
            this.emit('end');
        });
    }

    getTemperature() {
        this.socket.write('~M105\n');
    }

    waitFor(cmd: string) {
        return new Promise((resolve) => {
            this.socket.on('data', (data) => {
                if (data.toString().startsWith(cmd)) {
                    resolve(data);
                }
            });
        });
    }

    matchData(data: Buffer): {
        cmd: string,
        data: any
    } {
        try {
            const cmd = data.toString().match(new RegExp('CMD (?<CommandId>[MG][0-9]+) Received\.'));
            if (cmd && cmd.groups && cmd.groups.CommandId) {
                if (cmd.groups.CommandId === 'M28') this.sending_gcode = true;
                if (cmd.groups.CommandId === 'M29') this.sending_gcode = false;
            }
            if (this.sending_gcode) return { cmd: 'M28', data: data.toString() };
            return {
                cmd: cmd!.groups!.CommandId,
                data: data.toString().replace(new RegExp('CMD (?<CommandId>[MG][0-9]+) Received\.\r\n'), '')
            }
        } catch (e) {
            console.log(e);
            return {
                cmd: '',
                data: ''
            }
        }
    }

    writeCode(code: string, data: string = '') {
        this.socket.write(`~${codes[code]} ${data}\r\n`);
    }

    connect() {
        this.socket.connect(this.conopt)
    }

    printGCode(gcode: Buffer, name: string) {
        console.log(gcode.length, name);
        this.writeCode('file_start', `${gcode.length} 0:/user/${name}`);
        let count = 0;
        let offset = 0;
        while (offset < gcode.length) {
            let crc: number;
            let packet: Buffer;

            let dataSize = 0;
            if (offset + 4096 < gcode.length) {
                packet = gcode.subarray(offset, offset + 4096);

                const crcResult = crc32(packet);
                crc = crcResult;
                console.log(crcResult.toString(16));
                dataSize = 4096;
            }
            else {
                // Every packet needs to be the same size, so zero pad the last one if we need to.
                const actualLength = gcode.length - offset;
                const data = gcode.subarray(offset, actualLength + offset);

                // The CRC is for the un-padded data.
                const crcResult = crc32(data);
                crc = crcResult;
                console.log(crc.toString(16));

                packet = Buffer.alloc(4096);
                for (let i = 0; i < data.length; ++i) {
                    packet.writeUInt32LE(data[i], i);
                }

                packet.fill(0, actualLength, 4096);

                dataSize = actualLength;
            }

            // Always start each packet with four bytes
            const bufferToSend = Buffer.alloc(4096 + 16);
            bufferToSend.writeUInt16LE(0x5a, 0);
            bufferToSend.writeUInt16LE(0x5a, 1);
            bufferToSend.writeUInt16LE(0xef, 2);
            bufferToSend.writeUInt16LE(0xbf, 3);

            // Add the count of this packet, the size of the data it in (not counting padding) and the CRC.
            bufferToSend.writeUInt32BE(count, 4);
            bufferToSend.writeUInt32BE(dataSize, 8);
            bufferToSend.writeUInt32BE(crc, 12);

            // Add the data
            for (let i = 0; i < packet.length; ++i) {
                bufferToSend.writeUInt8(packet[i], i + 16);
            }

            // Send it to the printer
            fs.appendFileSync('log.txt', `Sending packet ${count} ---\n${bufferToSend}\n---\n`);
            this.socket.write(bufferToSend);

            offset += 4096;
            ++count;
        }

        this.socket.write('\n');
        this.writeCode('file_end');
    }
}

export default Connection;

codes.ts

export default {
    M601: 'start',
    M602: 'end',
    M115: 'info',
    M119: 'endstop',
    M105: 'temp',
    M27: 'status',
    M146: 'led',
    M23: 'print',
    M36: 'stop',
    M28: 'file_start',
    M29: 'file_end',
    M108: 'stop_heat',
    M651: 'fan_on',
    M652: 'fan_off',
    M114: 'position',
    M112: 'estop',
    M18: 'motor_stop',
    M17: 'motor_start',
    G92: 'set_zero',
    M610: 'change_name',
    G1: 'bed_move',
    M140: 'bed_temp',
    M104: 'extruder_temp',
    start: 'M601',
    end: 'M602',
    info: 'M115',
    endstop: 'M119',
    temp: 'M105',
    status: 'M27',
    led: 'M146',
    print: 'M23',
    stop: 'M36',
    file_start: 'M28',
    file_end: 'M29',
    stop_heat: 'M108',
    fan_on: 'M651',
    fan_off: 'M652',
    position: 'M114',
    estop: 'M112',
    motor_stop: 'M18',
    motor_start: 'M17',
    set_zero: 'G92',
    change_name: 'M610',
    bed_move: 'G1',
    bed_temp: 'M140',
    extruder_temp: 'M104',
} as Record<string, string>;

Unable to see Camera V 1.1.143

On the status page (both windows 10 app and windows native exe) i see the Camera Line, but no link for "view feed" I know the camera works because i can navigate to http://IP:8080/?action=stream and get the feed just fine.
Printer firmware is v1.2.1
Note, i haven't used an earlier version of this app, so i dont know if this is a regression or not.
I've seen this every time i've used the app (when i've submitted a gcode file through the app, as well as just connecting to the printer after i've submitted it via flashprint (and then disconnected from flash print so i could open this app)
image

Show file printing progress

Originally, FlashPrint shows file printing progress in a corner, based on the slicer's calculations for printing. This is possible because of the specifications for the GX file, also known as XGCODE file.

According to my own research about a year ago, I found out that GX files are essentially GCODE files, without any comments and with a custom binary header. I documented, as best as I could, my findings in this Excel spreadsheet based on the findings by another person which I can't recall at this moment.

I tried to fiddle manually with GX files using a hex editor to varying degrees of success, as well with GCODE files generated with different slicers, mainly Cura and Simplify3D, in an attempt to forge custom GX files. Most of the time, bed and extruder temperatures were incorrect because of reasons I couldn't tackle at the time I researched this topic.

Now, all of this might be helpful to tackle the printing progress and time calculations for GX files and GCODE files.

Connection to camera lost after some time (v1.2.102 )

I have noticed the change in the way the app connects to the camera of the printer as a result of #28. I had the same problem, that the link to the camera feed would never show up. I downloaded the updated version and it is working now, for a while.

After some time (30 to 60min in my few tests) the app loses the connection to the camera.
In the Resource Monitor, lots of connections start showing up.
Resource Monitor many Conenctions
After some time they disappear.
Resource Monitor one Connection

After this happens I can't reconnect to the camera, not through Adventurer Client nor through VLC or the Browser.
I have to turn the printer off and back on to enable it again.

Printing percentage complete data

Hi Andy, I have run some comparitive TCP dumps from the flashprint software and the adventure client.
I see the ADV client checks ~M119 and ~M105 to get the data it shows on the status page.
Flashprint also check ~M27 to capture the Percent complete.
I think just adding a query to ~M27 would provide you the ability to display Percent complete. Thoughts?
TCP REQUEST FOR M27 ~M27
TCP RESPONSE TO M27 REQUEST CMD M27 Received. SD printing byte 72/100 ok

Camera not found

I try to switch to Manual Mode – Camera so I can use it but it continue to say "camera not found" after like 3 seconds of waiting. I really dont know what I should do. Maybe you can help me? : )

Progress bar while sending file to printer

While sending large files, there's no way to know the file is being sent until the success message is shown.

If no progress bar is possible, show that a file is being sent until the process is completed.

file format error

when sending to printer adventurer gives file format error
even with extension changed to .G

Add Support For Camera

Add support for viewing the feed from the built-in camera of the printer of the printer.

Requirements:

  • Add additional page for viewing the camera
  • Show live view of automatic refreshing photo form the camera when the camera page is selected
  • Detect when the camera is disabled on the printer and show instructions for how to enable it (Disable USB support on printer)

File Transfer Failure when transfering to Adventurer 4

TL:DR When transfering a .gx file from my pc to my Adventurer 4, the file shows as complete in Adventurer Client, but the AD4 shows "Failed to open the file". The same file is able to be transferred and prints via Flashprint 5, or via USB.

I've done some sniffing of the file transfer, and I see a few differences between the Flashprint 5 transfers and the Adventurer Client. They are:

  1. Packet size: Flashprint sends a packet size of 4150 (TCP of 4096), while AC sends varying sizes up to 64294.
  2. ACK Number: Flashprint sends an ACK number of 800, while AC sends an ACK number of 882
  3. Last Packet: Flashprint completes the file transfer with a final packet similar to the rest, while AC sends a final packet flagged by wireshark as an "ESP" packet, a TCP Encapsulation of an IPsec Packet with a Security Payload.
  4. M29 command: Flashprint sends a packet following the last file data packet with a M29 command

Relevant Versions:

AD4 Firmware: V2.2.4-2.3
AC Version: 1.3.142
Windows 10 Pro Version: 22H2
OS Build:19045.2604
Windows Feature Experience Pack: 120.2212.4190.0

Example .gx file attached
Example AC logs from Debug Tab for gx file
For Wireshark captures, PC is .48 and the AD4 is .24
Wireshark capture for AC transfer failing:
Notes:
The last file packet is # 1472, M29 command looks to be also at the very end of 1472.
The AD4 seems to accept the M29 command in packet # 1501,
The M23 command is sent #1506 (to 0:/user/test_transfer.gx (ends with 0x0a LF)
The AD4 seems to accept the M23 command in #1510 ok, but Size of 0.

Wireshark capture for Flashprint transfer working:
Notes:
Last file packet is # 3491,
M29 command is # 3496.
M23 command is # 3499 (to 0:/user/test_transfer.gx (starts 0x7e ends with 0x0d0a -CRLF)
M23 command is received in 3501, shows received, opened, with a Size of 4693967, FIle ok.
M119 command is sent in 3503.
M119 command is received in 3504

AC_AD4_Transfer_failure.zip

If Connection To Printer Is Lost, App Requires Manual Disconnect

If the connection to the printer is interrupted, the app the app will continue to look connected, but the status data will be blank, and it will no longer function. To get it working again, you need to manually press the disconnect button and reconnect.

To reproduce:

  1. Connect to printer
  2. Disconnect network form PC
  3. Reconnect network
  4. Try and use app

Expected results:
App should show an error and attempt to reconnect, if reconnection is not possible then the user should be returned to the connection screen.

Worked once, now...

Great app, however it now won't take the IP address of my printer as valid...?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.