andycb / adventurerclientjs Goto Github PK
View Code? Open in Web Editor NEWAn unofficial cross platform client for working with the Monoprice Voxel or Flashforge Adventurer 3
License: MIT License
An unofficial cross platform client for working with the Monoprice Voxel or Flashforge Adventurer 3
License: MIT License
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.
Great app, however it now won't take the IP address of my printer as valid...?
Keep a list of previous IP adresses for quick reference when reopening the app.
Add support for viewing the feed from the built-in camera of the printer of the printer.
Requirements:
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!
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;
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>;
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)
Reproduces on app version 1.1.
Expected: The status data should be immediately shown
Actual: Large delay (2-3 seconds) where row headers shown but no data.
When running on Windows, the status page is 11px short small and a small scroll bar is shown.
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
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.
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:
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.
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.
After some time they disappear.
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.
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? : )
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:
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
when sending to printer adventurer gives file format error
even with extension changed to .G
Switch the app to a dark style when the OS is in dark mode
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.