Skip to content

Cameras

The machine has two cameras, one in the lid and one in the print head (The cameras). ForgeFIRM serves both over plain HTTP from the web control panel: MJPEG for anything that can read a stream of JPEGs, and an H.264 live stream for clients that decode video (the panel uses it when the browser can). There is no app, no cloud relay, and no proprietary protocol. This page tells you the one rule that governs the cameras, how to watch them, and what you get.

Read the Safety page first

ForgeFIRM is not the manufacturer's firmware. Read Safety before you run a job.

The sensors, what they can do, and the 8 MP status are in The cameras. The pipeline, the lighting, the camera-path sharing, and why the image looks the way it does are in The video pipeline.

The lid camera only works with the lid closed

The lid camera captures nothing while the lid is open. Not the live view, not a snapshot, and not an image requested in cloud mode. Close the lid and everything works; open it and the lid camera stops. The lid camera is mounted in the lid, so raising it swings the camera up to face the room; the enclosure being shut is the condition for a lid camera image to exist at all.

The head camera looks straight down at the bed, so it sees only the bed and the material even with the lid open. The panel can still show it with the lid open, and so can an extension package that has the head camera permission, such as the alignment tool, which lets you place material while you watch where the laser will hit. Everyone else gets the lid rule for the head camera too: cloud mode's image actions, the mjpg-streamer aliases, a Grbl sender's camera view, and any program that reads with the camera key or the open reads.

A stream the lid rule covers ends within about a frame of the lid opening. A refused capture never raises the lamps.

Situation What happens
Lid camera snapshot or stream requested with the lid open 409 naming the lid; no image data
Head camera, lid open, from the panel or an extension package the picture, as with the lid closed
Head camera, lid open, from anyone else 409 naming the lid; no image data
Lid opened while a stream is running the stream ends cleanly, unless it is the head camera and the panel or an extension package is watching
Lid state unreadable treated as open
Cloud service asks for an image with the lid open refused, and reported back as a failed action rather than left hanging
Lid closed again everything works immediately; nothing to restart

GET /cam/status reports it: capture_allowed is false whenever the lid is open, and stopped_by_lid records that the last capture ended because the lid opened rather than going idle. The panel's live view says lid open: the lid camera is off rather than showing a stream error.

The lid signal is the same one the hardware safety chain uses to gate the beam, the series combination of both lid switches, and the check fails closed: if the lid state cannot be read, the cameras stay dark.

It is a rule enforced by the two programs that own the sensors, not a hardware cut-off - the sensor rails stay powered, and root on the machine can bypass it. There is deliberately no setting to turn it off.

Watching it

In the panel. Open https://<machine-ip>/ and go to the Status tab. The Lid camera card shows a still by default with Live and Refresh buttons; Live switches the same frame to the running stream (H.264 when the browser supports it, MJPEG otherwise), and Stop returns to the snapshot.

From another program. The endpoints are:

URL What it returns
/cam/stream?cam=lid continuous MJPEG (multipart/x-mixed-replace)
/cam/stream?cam=head the same, from the head camera
/cam/h264?cam=lid continuous H.264 as fragmented MP4: the same picture in a fraction of the bytes, for clients that decode video
/cam/snapshot?cam=lid one full-resolution JPEG
/cam/snapshot?cam=lid&res=half one half-resolution JPEG (much faster)
/cam/snapshot?cam=lid&background=1 the same, but refused with 409 while somebody is watching a camera, and while a job is armed
/cam/snapshot?cam=lid&q=1..100 a JPEG at the given quality
/cam/status JSON: which sensor, which camera, frame rate, frame sizes, whether the lid currently permits capture
/?action=stream the lid stream again, under the name mjpg-streamer clients expect
/?action=snapshot one full-resolution lid JPEG, same aliasing

The ?action= pair exists because a lot of software (print-server dashboards, camera widgets, anything written against mjpg-streamer) assumes those exact URLs. Point such a client at http://<machine-ip>/ and it works.

Every one of them answers 409 with the lid open, so a client that checks status codes can tell "close the lid" apart from "the camera is broken".

Access. Reading the camera needs no login by default. The read-only routes answer any client on your network, over plain HTTP on port 80 or over HTTPS. A browser request must not be cross-site; that is what stops a hostile page in another tab from reaching into your machine. The setting panel_open_reads=0 closes the reads to logged-in sessions and the machine itself (Settings). Anything that changes machine state needs a login (The control panel).

The camera key. A program with no login, a Grbl sender or a stream viewer, reads the cameras with the machine's camera key. Press Camera URL on the Status tab's lid camera card: the panel shows the stream and snapshot URLs with the key in them, ready to paste. The key is a key query parameter, or the X-ForgeFIRM-Camera-Key header, on any read-only route, over HTTP or HTTPS, with the reads open or closed. It authorizes reads and nothing else. New key on the same card makes a fresh one; every URL that carried the old key stops working. Treat the URL as a password for the camera image.

LightBurn consumes the lid stream for its camera overlay while it drives motion over the Grbl connection; the two coexist.

What you get

5 MP machine (OV5648) 8 MP machine (OV8856)
Sensor frame captured 2592 × 1944 3264 × 2448
Live stream 1296 × 972 1632 × 1224
Full snapshot 2592 × 1944 3264 × 2448
Half snapshot 1296 × 972 1632 × 1224
Stream formats MJPEG (quality 75 by default) and H.264 (about 1.5 Mbit/s by default) same
Frame rate 15 fps sustained not measured; no 8 MP machine has been tested (The cameras)

Measured on a 5 MP machine: 15.0 fps with a viewer attached, which is the rate the sensor itself produces in this mode; the machine is not the bottleneck. With the NEON demosaic feeding the hardware JPEG encoder, the daemon uses about 41 % of one CPU with one viewer, and LightBurn can watch the stream while jogging from the same session without disturbing motion. With the GPU demosaic feeding the H.264 stream, the stream's CPU cost drops to bookkeeping: about 14 % of the CPU for one viewer. A full-resolution still takes about 2.4 s to produce (2.7 s if the camera has to be started first), because 5 megapixels of demosaicing and JPEG encoding happen on the machine's CPU.

The live view is exactly half the capture in each axis because each 2 × 2 group of sensor pixels becomes one output pixel, rather than the frame being scaled down. That is what makes it cheap enough to run continuously (The video pipeline).

The image is the sensor's data, demosaiced and encoded, with fixed exposure and no tone curve; compared with a phone photo it looks flat, and that is expected. Nothing is recorded on the machine: if you want a recording, record the stream on the computer watching it (The video pipeline).

When something looks wrong

No picture at all, and a 409 mentioning the lid. Working as intended: the lid is open, and this camera or this viewer is under the lid rule. Close it. /cam/status shows capture_allowed: false while that is the case. If the lid is shut and you still see this, one of the two lid switches is not making, the same condition that would stop the laser firing, so it is worth investigating rather than working around.

A black or nearly black picture. The scene is not lit: the exposure is fixed, so the camera cannot compensate. Check the lid_lamp_idle setting (Settings), and remember snapshots can carry their own lamp=0..1023 level for one image.

The stream stops on its own. Either the lid opened (the panel says so), or someone else (another browser tab, LightBurn, the panel) asked for the other camera, or for a stream, and preempted yours. Reload; the panel does this automatically and says which it was.

"camera switch timed out". A viewer would not let go within the grace period. Close the other viewer and retry.

A snapshot returns 503. The camera could not start. The usual cause is another process holding the capture device; the daemon's log names the failing step (Logging).

/cam/status reports "sensor": "unknown". No camera was found on that bus, or a sensor bound that this firmware has no profile for. On an 8 MP machine see The cameras.