The Glowforge CNC laser does very little on its own. It is essentially a ‘dumb terminal’ that needs to be given detailed instructions about what to do. It receives these instructions from the company’s cloud service. In this post, I’ll describe how the device communicates with the cloud service.
Authentication
The device sends the following login request to https://app.glowforge.com/machines/sign_in:
POST /machines/sign_in HTTP/1.1
Host: app.glowforge.com
Accept: */*
Content-Type: application/json
Content-Length: 103
{"serial": "<SERIAL#>", "password": "<PASSWORD>"}
The serial number and password are burned into the one-time programmable registers in the i.MX6 processor on the control board.
If the authentication to the service is successful, the service responds with:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: close
Status: 200 OK
Cache-Control: max-age=0, private, must-revalidate
X-XSS-Protection: 1; mode=block
X-Request-Id: <REQUEST_ID>
ETag: W/"<E_TAG>"
X-Frame-Options: SAMEORIGIN
X-Runtime: 0.218339
X-Content-Type-Options: nosniff
Date: <DATE/TIME>
Set-Cookie: request_method=POST; path=/
X-Powered-By: Phusion Passenger 5.1.7
Server: nginx/1.10.3 + Phusion Passenger 5.1.7
309
{"ws_token":"<WS_TOKEN>","auth_token":"<AUTH_TOKEN>"}
0
The ws_token
token is used to authentication with the WebSocket service, and the auth_token
is used to authenticate to the service’s various API’s.
WebSocket
The primary path for two-way communication between the device and the service is through a persistent WebSocket session. This session remains active for as long as the device is powered on.
To establish the connection, the device opens a connection to wss://status.glowforge.com and sends the following:
GET /<WS_TOKEN> HTTP/1.1
Pragma: no-cache
Cache-Control: no-cache
Host: status.glowforge.com
Origin: http://status.glowforge.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <WS_SESSION_KEY>
Sec-WebSocket-Protocol: glowforge
Sec-WebSocket-Version: 13
The WS_TOKEN
is the authentication token we received during the login, and the WS_SESSION_KEY
is the first part of the WebSocket protocol handshake.
To establish the session, the server responds with:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: <WS_SESSION_KEY_RESPONSE>
Sec-WebSocket-Protocol: glowforge
We now have a WebSocket session established, and from here on, the communications are in binary using the WebSocket protocol. To make it easy to understand, I’m only going to show the decoded JSON exchanges between the device and the service.
Messages
The communication between the device and the service are composed of messages. The following message types have been observed:
Log: DEVICE to SERVICE
{"id":41,"timestamp":8079,"type":"log","version":1,"log":"hw: clearing pulse data","level":"INFO"}
These messages are simple log entries sent up to the cloud. They cover many of the same events that are recorded to the device’s local log files. When developing the Glowforge Emulator, it seemed that the service didn’t mind if it didn’t receive these.
Action: SERVICE to DEVICE
{"id":3116308,"action_type":"lid_image","machine_serial":"<DEVICE_SERIAL>","status":"ready"}
These are the commands sent from the cloud down to the device. The commands that have been observed are: settings
, lid_image
, head_image
, hunt
, motion
, and print
.
Event: DEVICE to SERVICE
{"id":451,"timestamp":215043,"type":"event","version":1,"action_id":3116308,"event":"lid_image:received","log":"state=ready","level":"INFO"}
The device responds to action messages using the same action_id
. There are prescribed events that the service expects from the device. If any of these are missed, the service will send another action message with the same action_id
with the status
field set to “cancel”.
A full listing of the event messages that are sent in response to each of the action types is documented in the Glowforge Emulator source.