Crestron Programming Basics
Introduction
A control system is a small computer with a program on it, wired to everything else in the room, whose job is to make a complicated set of equipment behave like a single appliance. Somebody presses one button and a projector wakes, a screen lowers, a switcher routes, lights dim, and an audio system comes up at the right level. That is the whole product, and the program is the thing that does it.
This book is about the program and the protocols under it. Not the syntax of any one manufacturer's tool — that is learned from the tool, and it changes more often than a book can follow — but the ideas and the wire-level facts that are the same on every platform and that nobody explains. What a control system actually sends down a cable. Why four serial settings must match before anything works at all. What a device says back, and what it means when it says ERR3. Why one-way control is the root of most unreliable rooms. And how to write a program you will still be able to debug in a year, under pressure, having forgotten it.
It is written around real specifications, because control programming is a reading job as much as a writing one. The one standard device-control protocol worth knowing properly is examined command by command, so that the next manufacturer's protocol document — which will be laid out differently and documented worse — is readable.
It assumes AV Fundamentals 101 and Networking Basics. Nothing else.
How to Use This Book
Read it in order the first time. It runs outward from the cable: what a control system is, what it is made of, the ways it reaches a device, serial and then IP, a real protocol in detail, then feedback, logic, interface, debugging and handover.
Keep a notebook
One page per device you ever control, with five things: the control method, the settings or the address and port, the command that turns it on, what it says back, and the thing about it that surprised you. That last column is the valuable one. Devices misbehave in specific, repeatable ways, and a programmer with two years of that notebook is dramatically faster than one without, because half of this job is remembering that this projector needs a second command after warm-up.
A note on the words
Control programming has a lot of near-synonyms and they cause real confusion. A "signal" in a control program is a named value inside the program, not an audio or video signal — this book says "control signal" where there is any doubt. A "driver" or "module" is a reusable block of logic for one device. A "symbol" is a logic block in some tools. "Join" numbers connect a panel's buttons to the program. And "feedback" means two different things: the program telling a panel what to light, and a device telling the program what it is doing. Both appear here and the text says which.
A note on safety
Control programming is the one discipline in this series that can cause harm from a desk. A program commands motorised equipment: screens, projector lifts, shades, and sometimes heavier rigging. A lift that descends into an obstruction, or a screen that runs while somebody is working underneath it, is a real injury risk and the mechanism does not know you made a mistake. So motorised equipment gets interlocks, limits and a way to stop it that does not go through your program, and nothing in this book qualifies you to decide what a given motorised load needs — that is the installer's and the manufacturer's call, and you should ask.
Two more. A program can command an audio system to full output, and a wrong level sent to a system in a room with people in it is a hearing risk, so output levels get clamped in the program rather than trusted to a user interface. And the physical work around this discipline is the usual AV mix of mains power inside racks and ladder work to reach panels and projectors, often alone; a heavy display on a bracket is a two-person lift whatever the schedule says.
What a Control System Is For
A control system does one thing: it makes a room full of separate equipment behave like one appliance. Everything else in this book is in service of that, and the commonest mistakes come from misunderstanding what it is not.
One panel, one tap, and the whole room responds — that is the promise of AV control.
One interface, and what the user sees
The user sees a panel with a few buttons. Behind those buttons is a program that knows the room: which projector, on which input, fed from which switcher output, with which audio source at which level, and what order all of that has to happen in. Press "Laptop" and a dozen commands go out in a sequence somebody worked out.
That is worth stating as a design brief rather than a description, because it tells you what good looks like. The measure of a control system is not how many features it exposes; it is how few decisions the user has to make to get what they came for. A panel with twenty-five buttons has usually failed, and it has usually failed because the programmer exposed the system's structure instead of hiding it.
The second measure is honesty. When the user presses a button, the panel should show what actually happened — not what was requested. That distinction is the subject of a whole chapter later, and it is the single biggest difference between rooms people trust and rooms people avoid.
What a control system is not
It is not a signal path. Audio and video do not travel through the control processor. The processor tells a switcher what to route; the video goes through the switcher. A reader who confuses the two will look for a picture problem in the program, and there is nothing there to find.
It is not a network. The control system uses the network to reach devices, and the network is somebody else's design. If a device cannot be reached, that is an addressing or a switch question, and the networking courses cover it.
It is not a replacement for a device's own configuration. A projector's picture settings, a DSP's processing, a camera's exposure — these live in the device and are set up there. A control system recalls presets and sends commands; it does not configure.
And it is not clever. The program does exactly what it was written to do, in order, every time. When a room misbehaves intermittently, the program is usually the least likely culprit, because programs do not have moods. What they do have is assumptions about devices, and that is a different chapter.
One consequence worth carrying through the whole book: a control system's job is only possible because devices can be told things and can say things back. The rest of the trade thinks about signal. This discipline thinks about commands and responses, which is why the next several chapters are about exactly those.
How to do it
- List every device the system must control, and what it must be able to do to each.
- For each device, establish how it can be controlled and whether it can report back.
- List what the user must be able to do, in the fewest words possible.
- Separate control from signal path, and draw the signal path separately.
- Find out who configures each device, because that is often not you.
- Ask what happens when each device is already on, or already off, or absent.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| A picture problem is being chased in the program | Confusing control with signal path | Video does not pass through the processor; look at the switcher and the cables |
| A device cannot be reached and the program is blamed | Addressing or network reachability | Prove the device responds outside the program first, always |
| The panel has twenty-five buttons and nobody uses the room | The system's structure was exposed instead of hidden | Go back to what the user came to do; most of those buttons are for you, not them |
| Intermittent misbehaviour blamed on the program | Programs are deterministic; the variable is usually a device's state | Look for an assumption about a device that is sometimes false |
Practice it
For a room you know.
- Every device and every required action is listed.
- Each device's control method and feedback capability is known.
- What the user must do is stated in the fewest possible words.
- Control and signal path are drawn separately.
- You know who configures each device.
- The already-on and already-off cases have been considered.
Processor, Panel and the Wiring Between
Three things and the cables between them. What makes this chapter worth reading is not the list but what each part decides about the job, and which of its properties you will discover too late if you do not ask now.
Three elements: a brain, an interface, and connections to everything it controls.
The processor is a small computer
Treat it as one and everything about its behaviour becomes predictable. It boots, which takes time. It runs a program you load onto it, and it keeps running it until it is stopped. It has an address on the network, a filesystem, firmware that can be out of date, and a finite amount of memory and processing. It logs. It can be connected to and inspected while it runs.
Four properties to establish before you design anything. How many serial, infrared and relay ports it has, because that number is a hard constraint and expansion costs money and rack space. Whether its firmware is current, because a program built for one firmware version may not load on another. What it does on power-up, specifically how long it takes to be useful — a room whose processor takes ninety seconds to boot needs a different design from one that takes fifteen. And how you get into it to look at what it is doing, which is the subject of the debugging chapter and should be established on day one rather than during a fault.
One more, learned painfully by everybody: know where the program source lives and keep it. A processor holds a compiled program. If the source is on a laptop that was reimaged, the room cannot be modified again by anybody, and that situation is depressingly common.
Panels, keypads and the things people touch
A touch panel is a screen the program draws on and reads presses from. It is connected over the network in almost all modern systems, it has its own firmware, and the layout is a separate file from the program — which means they can disagree with each other, and the symptom of that is a button that does nothing.
Button panels and keypads have no display, so they cannot show state except through backlighting, and that limitation shapes what they can sensibly be used for. A keypad is excellent for a few fixed actions and poor for anything with modes.
And increasingly the interface is somebody's own device, or a scheduling panel at the door, or a voice assistant, or nothing at all — a room that senses occupancy and configures itself. Each of those changes what feedback is possible, which is why the interface decision belongs at the start of a design and not at the end.
The wiring, and how a command actually flows
Follow one button press all the way through, because this is the mental model the rest of the book assumes.
The user touches a button. The panel sends a message over the network to the processor identifying which button, by number. The program sees that as a control signal going high. Logic in the program decides what that means given the room's current state, and produces one or more outputs. Each output is wired to a device driver, which turns it into the actual bytes that device expects. Those bytes leave the processor through a port — a serial port, an infrared emitter, a relay contact, or a network socket. The device receives them and acts. If the device can report back, its response comes in the same way reversed, through the driver, into control signals the logic can use, and out to the panel as feedback so the button can light.
Six stages, and a fault lives in exactly one of them. The troubleshooting value of holding that sequence is enormous: a button that does nothing is a panel-to-program problem, a device that does not respond is a program-to-device problem, and a button that lights when the device is off is a feedback problem. Three completely different investigations, and the appearance tells you which.
A word on the wiring itself, because it is where the method is decided. Each control port on the processor is of a particular kind — serial, infrared, relay — and the port decides the method available to whatever is plugged into it. A processor's control port count is therefore a hard constraint on the design, every port has settings that must match the device at the other end, and a network-controlled device needs an address and a port number instead of a cable to the processor at all. The next chapter takes all five methods in turn.
How to do it
- Count the processor's serial, infrared and relay ports and compare against the device list.
- Check the firmware version, and whether the program you inherit matches it.
- Time the processor's boot to the point where the room is usable.
- Establish how to connect to it and read its log, before you need to.
- Find out where the program source is kept, and get a copy.
- List every interface device, its firmware, and where its layout file lives.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| A button on the panel does nothing at all | Panel layout and program disagree about the button's number | A panel-to-program fault; check the join number on both sides |
| Program will not load onto the processor | Firmware version mismatch | Establish the firmware before building, not after |
| The room cannot be modified by anybody | Program source lost; the processor holds only the compiled program | Keep the source somewhere the organisation controls, from day one |
| Room is unusable for the first minute after a power cut | Processor boot time, which is a design input | Time it, and design the room's startup behaviour around the real figure |
| Ran out of ports halfway through the job | Port count never checked against the device list | Count first; expansion costs money and rack units |
Practice it
On any control system you can reach.
- Port counts are checked against the device list.
- The firmware version is known and matches the program.
- Boot time has been measured.
- You can connect to the processor and read its log.
- The program source is held somewhere safe and you have a copy.
- Every interface device and its layout file is accounted for.
The Five Ways to Control a Device
There are five, every device offers some subset, and the choice you make decides whether you will ever know what that device is doing. That makes it the most consequential early decision on a control job.
The five
Serial. A cable from a processor port to the device, carrying bytes both ways. Reliable, two-way, and dependent on four settings matching. The traditional backbone of this discipline and still the most dependable method there is.
Infrared. An emitter stuck over the device's receiver, sending the same codes its remote does. One-way with absolutely no exception: the device cannot answer and does not even know whether it received anything. Cheap, universally available, and the cause of more unreliable rooms than everything else combined.
Relay, or contact closure. The processor closes a pair of contacts and something happens — a screen descends, a lift moves, a legacy device triggers. One-way, mechanically simple, and genuinely the right answer for motorised equipment and for anything that offers no other method. Some devices offer a sensing input in return, which is a primitive but real form of feedback.
IP. A network socket to the device, usually TCP, carrying a text or binary protocol both ways. Two-way, no cable from the processor, and the direction everything is moving. It brings session behaviour, authentication and reachability questions that serial does not have.
The device's own interface. An HTTP API, a vendor SDK, a cloud service, or a published module somebody else wrote. Increasingly common, usually two-way and rich, and it ties you to that manufacturer's documentation and release cycle.
| Method | Two-way | Needs | Right for |
|---|---|---|---|
| Serial | yes | a cable and four matching settings | anything that offers it |
| Infrared | no, never | a clear line of sight | last resort only |
| Relay | no, unless a sense input exists | a pair of contacts | motors and legacy gear |
| IP | yes | an address, a port and reachability | most modern devices |
| The device's own API | usually | documentation and sometimes credentials | rich control, if documented |
Choosing a control method, and the rule that follows
Choosing a control method comes down to one rule, and it is short: choose the method that gives you feedback, every time, even if it is more work. Which method, for which device, is then mostly a practical question.
The reason is the whole of the feedback chapter later, but in brief: a device you can interrogate lets the program know the room's real state, which means the panel can be honest, the program can recover from somebody using the device's own remote, and a failure can be reported rather than silently producing a dark room. A device you cannot interrogate forces the program to guess, and every guess is a future fault.
So if a projector offers serial and infrared, use serial. If it offers IP and serial, either is fine and the choice is practical — serial has no reachability or session problems, IP has no cable. If a device offers only infrared, treat that as a finding worth reporting at design stage rather than a constraint to be quietly absorbed, because it caps what the room can be.
Two practical notes. Infrared is not always avoidable and when it is not, mitigate: send discrete commands rather than toggles wherever the device has them, since a discrete "power on" is idempotent and a toggle guarantees the room will eventually be inverted. And relays for motorised equipment are often correct precisely because they are simple, but they must respect the equipment's own limits and interlocks rather than relying on your timing.
How to do it
- Find the device's control documentation before assuming anything about it.
- List every method it offers, not just the one in the brochure.
- Prefer any two-way method over any one-way method.
- Between serial and IP, choose on reachability and cable practicality.
- Where only infrared exists, report it and check for discrete commands.
- For motorised equipment, check what interlocks and limits the device provides.
- Record the chosen method and why, per device.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| Room state and panel state disagree after somebody uses a remote | One-way control, so the program cannot see what happened | Choose a two-way method; this is the fault that defines one-way control |
| Everything is inverted — on means off | Infrared toggle commands and a missed transmission | Use discrete commands where they exist; toggles guarantee this eventually |
| Infrared works at the bench and not in the room | Emitter placement, ambient light, or the device moved | Line of sight is a physical dependency with no error reporting at all |
| A motorised screen ran into an obstruction | Relied on program timing rather than the equipment's own limits | Motorised equipment needs its own limits and interlocks, not your delays |
Practice it
For a real device list.
- Every device's documented methods are listed.
- A two-way method is chosen wherever one exists.
- Every one-way device is recorded as a known limitation.
- Infrared uses discrete commands wherever available.
- Motorised equipment relies on its own limits, not your timing.
- The choice and the reason are written down per device.
Serial Control, and Getting It Right
Serial is the most dependable method in this discipline and it refuses to work at all until four numbers match. Almost every "the serial is not working" call is one of those four, and the rest are in the handful of settings nobody thinks about.
To command a display or an amp, the processor must speak each device's language.
The four that must match
A serial connection has no negotiation. Both ends simply assume a configuration, and if they assume differently you get nothing, or you get recognisable rubbish — which is actually the more useful outcome, because rubbish means the cable is fine and the settings are wrong.
Baud rate is the speed. The common values are 9600, 19200, 38400, 57600 and 115200, and 9600 remains extremely common on AV devices because the commands are tiny and speed buys nothing.
Data bits is how many bits carry each character, almost always eight and occasionally seven on old equipment.
Parity is an error-check bit, and it is usually none. Where a device wants even or odd, it will say so, and getting it wrong produces characters that are nearly right.
Stop bits marks the end of each character, almost always one.
These are written as a shorthand — 9600,8,N,1 — and that string is what you ask a device's documentation for and what you set on the processor's port. Get the string and the job is halfway done. There is no way to discover it by experiment that is faster than reading the manual, although trying 9600,8,N,1 and then 115200,8,N,1 covers a remarkable proportion of devices.
The settings nobody thinks about
Beyond the four, a handful of properties exist and each has a device somewhere that needs it.
Flow control is how one end tells the other to pause. XON/XOFF does it with special characters inside the data stream; hardware flow control does it with dedicated wires, conventionally RTS and CTS. For short AV commands flow control is almost never needed and is usually set to none, and leaving it on when a device does not expect it is one way to get a connection that works for a while and then stops.
DTR and RTS are control lines that some devices use as more than flow control: a few legacy devices will not respond at all unless DTR is asserted, because they treat it as "something is connected". When a device is silent on a cable you have proved and settings you have checked, this is worth a thought.
BREAK is a deliberate, longer-than-a-character disturbance on the line, and a small number of devices use it as a reset or an attention signal. You will meet it rarely and be very glad you know it exists.
And then the cable. Serial has straight and crossed variants, the crossed one conventionally called a null modem, and a device expecting one and given the other is silent. Pin assignments vary, three-wire connections are common in AV, and a surprising number of devices use a non-standard connector with an adaptor that has been lost. The cable is the most common fault of all and it has no error message.
The serial settings a control programmer has to get right
The settings enumerated in RFC 2217, the Telnet Com Port Control Option, which exists to carry exactly these across a network. It is cited here rather than a serial-hardware standard because it is the readable authoritative list of what a serial connection is configured by.
| Setting | What it is | Typical AV value |
|---|---|---|
| Baud rate | The speed in bits per second | 9600, or 115200 on newer gear |
| Data bit size | Bits per character | 8 |
| Parity | An error-check bit | none, usually |
| Stop bit size | The end-of-character marker | 1 |
| XON/XOFF flow control | Pause signalling using characters in the data stream | none |
| Hardware flow control | Pause signalling using dedicated wires | none |
| The DTR signal | Data terminal ready — some devices need it asserted to respond at all | not needed, unless the device requires it asserted |
| The RTS signal | Request to send — used for hardware flow control and occasionally as a device requirement | not needed with flow control at none, unless the device requires it asserted |
| The BREAK signal | A deliberate line disturbance used by a few devices as reset or attention | rarely used |
| Notification of line changes | A device reporting that its control lines moved | rarely used in AV |
| Signature | A text string identifying the device server, which may include its make and version | set by the device server |
The first four are the ones that must match before anything happens at all, and they are the whole of most serial troubleshooting. The rest matter rarely and decisively: a device that stays silent on a proved cable with correct settings is very often a DTR requirement, and a connection that works briefly and then stops is very often flow control configured on one end only. Note also what this table implies about serial over IP — a device server has to carry all of these faithfully, which is why a cheap one will pass data and still fail with a device that cares about control lines.
How to do it
- Get the settings string from the device's documentation, not from memory.
- Identify the cable type the device expects, straight or crossed.
- Connect a laptop to the device directly, before involving the processor at all.
- Send the simplest command the documentation gives and watch for any response.
- If you get rubbish rather than nothing, the cable is fine and a setting is wrong.
- If you get nothing at all, suspect the cable, then DTR, then the port.
- Only once the device responds to a laptop, move the cable to the processor.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| Recognisable rubbish rather than a clean response | Baud rate or another of the four settings is wrong | Rubbish is good news — the cable works; work through the four settings |
| Nothing at all, on correct settings | Cable type, a lost adaptor, the wrong port, or an unasserted DTR | Prove the cable first, then consider DTR; a silent line gives no error |
| Works for a few minutes then stops | Flow control configured at one end and not the other | Set flow control to none at both ends unless a device demands otherwise |
| Works with a laptop and not through the processor | The processor's port settings differ, or the port is the wrong one | This is why you prove it with a laptop first; now only one thing changed |
| A device server passes data but one device still fails | Control lines not carried faithfully by a cheap server | Some devices need DTR or RTS; not every server conveys them |
Practice it
With a serial device and a laptop.
- You have the settings string from documentation.
- The cable type is correct and the cable itself is proved.
- The device responded to a laptop before the processor was involved.
- Flow control is set to none at both ends, or deliberately otherwise.
- The processor's port settings match exactly.
- The device's response is recorded in your notebook.
Control over IP
Control over a network is where the discipline is going, and it brings three things serial never had: a session that can be refused, credentials, and a device that can be unreachable while being perfectly healthy.
A socket, not a port
Controlling a device over IP means opening a TCP connection to an address and a port number and exchanging bytes. The protocol inside is usually the same text protocol the device offers on its serial port, which is why a device's documentation often has one command list and two ways to deliver it.
What changes is everything around the bytes. There is no cable to prove, so reachability becomes the first question and it is a networking question. There is a connection that can be refused, dropped, or timed out. There may be a password. And the device may allow only one connection at a time, which has a consequence worth stating loudly: if you are connected with a terminal to debug, the control system cannot connect. Hours have been lost to that, by everybody, at least once.
Many devices present a Telnet service, and a plain TCP connection to it is often enough. Some present a raw socket with no session protocol at all, which is simpler and better for this purpose. Some offer an HTTP API, which is a different shape — request and response rather than a conversation — and generally easier to test and harder to get unsolicited feedback from.
That last point is worth finishing, because there is an answer to it and the answer is increasingly what modern devices offer. HTTP is request-and-response by design: the client asks, the server answers, and the server has no way to speak first. So an HTTP-only control API leaves you polling, with all the cost the feedback chapter later describes. WebSocket exists precisely to fix that. It starts as an ordinary HTTP request carrying an upgrade, and once the handshake completes the connection stops being request-and-response and becomes a two-way channel where either side can send at any time.
For a control programmer the practical consequence is a question to ask of any device offering an HTTP API: is there a WebSocket endpoint as well? If there is, you can have unsolicited feedback and you should use it. If there is not, you are polling, and you should size the poll interval deliberately rather than discovering it. A device documented only as "REST API" is a device you will be polling.
Why a session misbehaves
Telnet is a real protocol rather than just "a socket", and that explains several confusing behaviours.
It defines a network virtual terminal — an idealised terminal both ends pretend to be talking to — and it negotiates options at the start of a connection, each side offering and agreeing capabilities. Those negotiations are sent as command bytes in the same stream as the data, which is the root of the confusion: a device doing proper Telnet negotiation sends your program bytes that are not part of any response, and a driver that does not expect them will parse them as garbage.
The same mechanism explains echo. Telnet negotiates who echoes typed characters, and a device that has decided to echo will send back everything you send it, so your program sees its own command arriving as if it were a response. A driver written without allowing for that will match on its own output and conclude the device said something it did not.
The practical approach: use a raw socket if the device offers one, because none of this applies. If it must be Telnet, test with a terminal first and watch exactly what arrives, including the negotiation at connection and any echo. Write the driver against what actually arrives rather than against what the command list implies.
Telnet also defines a standard set of control functions and a command structure, and the one worth recognising is that a device may expect a particular line ending. Carriage return, line feed, or both, is a real and common cause of a device ignoring perfectly correct commands, and it is worth trying all three when a documented command does nothing.
Connections, credentials and keeping them
Decide deliberately whether the program holds a connection open or connects per command. Holding it open is faster, allows unsolicited feedback to arrive, and occupies the device's single session if it has only one. Connecting per command is more robust against network interruptions and makes unsolicited feedback impossible. Most drivers hold connections open and reconnect on failure, and that reconnection logic is the part people forget — a program that loses a connection and never tries again produces a room that worked this morning.
Authentication is now normal and your driver must handle it. The pattern is almost always the same: on connecting, the device sends a prompt or a challenge, the program replies with credentials, and only then will commands be accepted. Some protocols specify this precisely, including the case where security has been deliberately switched off so that no authentication step occurs at all — and a driver that assumes one or the other will fail on half the devices it meets. Read the specification and handle both.
Finally, store credentials where the organisation controls them, not in a comment in the program. Control systems reach devices that matter and a program is handed around.
How to do it
- Get the address, the port and the protocol from documentation.
- Prove the device is reachable at all before anything else.
- Connect with a terminal and record every byte that arrives on connection.
- Note whether it authenticates, echoes, or negotiates options.
- Send one documented command and record exactly what comes back.
- Try each line ending if a documented command produces nothing.
- Find out whether the device permits more than one session, and write that down.
- Disconnect your terminal before expecting the control system to work.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| The control system cannot connect while you are debugging | The device permits one session at a time | Disconnect your terminal; everybody loses an hour to this once |
| Driver sees garbage at the start of every connection | Telnet option negotiation arriving in the data stream | Use a raw socket if offered, or handle the negotiation bytes |
| The program appears to receive its own commands as responses | The device is echoing, as negotiated | Write the driver against what actually arrives, not the command list |
| A documented command is ignored entirely | Wrong line ending — carriage return against line feed against both | Try all three; this is a very common and very cheap fix |
| Room worked this morning and no device responds now | Connection lost and the driver never reconnected | Reconnection logic is the part that gets forgotten |
| Device accepts the connection and rejects every command | Authentication step not handled | Read the specification; handle both the authenticated and the open case |
Practice it
With an IP-controlled device and a terminal.
- Address, port and protocol come from documentation.
- You have recorded what arrives on connection, before sending anything.
- Authentication behaviour is known and handled.
- The correct line ending is established.
- The session limit is known and written down.
- Reconnection behaviour exists and has been tested by unplugging something.
PJLink — a Standard Worth Knowing
One protocol is worth reading end to end, because every other device protocol you meet will be the same ideas laid out differently and documented worse. Learn to read this one and the rest become legible.
Why a neutral protocol exists
The specification states the problem in its own opening: as more manufacturers entered the projector and display market, each brought its own control system and command set, so control software from one manufacturer was useless for anybody else's equipment, and anybody running a large estate of mixed displays had to build something complicated. PJLink was standardised by a Japanese industry association to fix exactly that, so that one piece of software can control and monitor projectors and displays from different makers.
For a control programmer this is straightforwardly useful: a projector that supports it can be driven without hunting for a vendor-specific command list, and a mixed estate can be monitored uniformly. It is organised in classes, with a query that asks a device which class it supports, so a program can discover what it is allowed to ask for.
It is also the clearest worked example of a device protocol in existence, which is the real reason it is here.
Reading a command byte by byte
Every command line has the same five parts, with defined lengths: a header of two bytes, which is always a percent sign followed by a single digit giving the class; a command body of exactly four bytes; a one-byte separator, which for a command is a space; a transmission parameter of up to 128 bytes; and a one-byte terminator, which is a carriage return. Everything is ASCII, every command line without exception starts with the percent sign, and the command body is case-insensitive.
So turning a projector on is `%1POWR 1` followed by a carriage return. Percent, class 1, the four-byte body POWR, a space, the parameter 1, carriage return. Turning it off is the same with parameter 0.
A response has the same shape with one difference: the separator is an equals sign rather than a space. So a successful power-on produces `%1POWR=OK` and a carriage return.
Commands divide into two kinds. Set commands operate the device or change a setting, and their parameter carries the setting. Get commands ask for the current state, and their parameter is a single question mark — so `%1POWR ?` asks what the power state is, and the response carries the answer in the parameter position.
That is the whole structure, and it is worth dwelling on because it is the shape of nearly every text device protocol: a fixed prefix, a short mnemonic, a separator, a parameter, a terminator. Once you can see those five parts in a specification you can write a driver for almost anything.
| Part | Length | In a command | In a response |
|---|---|---|---|
| Header and class | 2 bytes | % then a class digit | the same |
| Command body | 4 bytes | a fixed mnemonic such as POWR | the same mnemonic |
| Separator | 1 byte | a space (0x20) | an equals sign |
| Parameter | up to 128 bytes | the setting, or ? for a query | the answer, or an error code |
| Terminator | 1 byte | carriage return (0x0d) | the same |
Discovery, notification and the data nobody uses
Three further capabilities are worth knowing because they exist in the specification, exist in the devices, and are almost never used by anybody's program.
Discovery. The specification defines a search protocol: a program broadcasts a search and devices on the network answer, announcing themselves with enough information to be identified. For a programmer this is genuinely useful on a commissioning day — rather than typing addresses from a schedule that may be wrong, you ask the network what is actually there and get back what actually answered. It is also the fastest way to find the display somebody moved.
Status notification. The specification also defines a notification protocol, in which a device reports a change without being asked. This is the unsolicited feedback of the next chapter, standardised: a projector that has been switched off at the wall, or has developed a fault, can say so rather than waiting to be polled. Where it is available it is better than polling, and most programs still poll slowly as well, because a notification you missed looks exactly like nothing having happened.
Maintenance data. This is the one that surprises people. A projector will tell you, over the same control connection you are already using, how many hours its lamp has run, how many hours its filter has run, and the replacement model numbers for both. Those queries have existed for years and essentially nobody's room program asks them.
Consider what that makes possible with an afternoon's work. A program that reads lamp hours and filter hours on startup, and emails somebody when either crosses a threshold, turns reactive maintenance into planned maintenance across an entire estate — and it does it with queries the devices already answer, over a connection that already exists, with no extra hardware at all. On a site with forty projectors that is the difference between replacing lamps during a timetabled visit and replacing them in front of a lecture theatre.
The same applies to the error status query, which asks a device to report its own fault conditions. A program that reads it and surfaces anything abnormal is doing monitoring, which is the thing the enterprise platforms are sold for, using data the device gives away.
If you take one piece of practical advice from this chapter, take this: ask every device you control what maintenance and error data it will give you, and do something with it. It is the cheapest value a control programmer can add and it is lying unused in nearly every room in the world.
What a device says back, and what each answer means
The response codes defined in Section 2 of the PJLink specification, which apply across its commands. This table is the most practically important thing in this chapter: a program that sends commands and ignores these has no idea whether anything it asked for happened.
| Response | Meaning | What a program should do |
|---|---|---|
| OK | Successful execution | Proceed. Note that a power-on sent to an already-on device also returns OK. |
| ERR1 | Undefined command — the device does not support it | Stop sending it. Check the class the device reports. |
| ERR2 | Out of parameter — the command is understood, the value is not | Fix the parameter. Often an input number the device does not have. |
| ERR3 | Unavailable time — right command, wrong moment | Wait and retry. This is the warm-up and cool-down case. |
| ERR4 | Device failure — it cannot continue to operate properly | Report it to a human. Retrying will not help. |
Three of these change how a program should be written. ERR1 means the command is wrong for this device, so a program should ask what class the device supports rather than sending hopefully. ERR3 is the one that matters most in a room: it means the command was right and the device was busy — warming up, cooling down, mid-transition — so the correct response is to wait and try again rather than to conclude failure, and a program that treats ERR3 as a failure will report a broken projector every single morning. And ERR4 is a hardware fault, which should reach a person rather than being retried silently forever. A program that distinguishes these three is a different class of product from one that sends and hopes.
How to do it
- Find the command structure section and identify the five parts and their lengths.
- Find the terminator, and the separator for both commands and responses.
- Write down the simplest set command and the simplest get command, byte by byte.
- Find the response code table and list every error the device can return.
- Decide what your program does for each error, especially the busy case.
- Find the query that reports what the device supports, if there is one.
- Test every command against a real device and record the exact response.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| A program reports a broken projector every morning | Treating a busy response as a failure during warm-up | Wait and retry on the busy code; it means right command, wrong moment |
| A command works on one projector and not another | Different supported classes or features | Ask the device what it supports rather than assuming |
| Commands are rejected for a parameter the documentation lists | That device does not have that input or feature | Out-of-parameter means understood but impossible on this unit |
| A program retries a hardware failure indefinitely | Not distinguishing a device fault from a transient one | A device-failure response should reach a person |
| Power-on returns success and the projector was already on | Specified behaviour, not a bug | Success does not mean something changed; query the state if you need to know |
Practice it
With any projector or display that supports a documented protocol.
- You can name the five parts of its command line and their lengths.
- You can write one set command and one get command byte by byte.
- You have listed every error response it can return.
- Your program does something sensible and different for each error.
- Busy responses cause a wait and retry rather than a failure report.
- Every command has been tested against real hardware and recorded.
Feedback, and Why One-Way Control Fails
This is the most important chapter in the book. Nearly every unreliable control system in the world is unreliable for the same reason: the program does not know what the devices are actually doing, so it guesses, and the guesses drift away from reality.
What goes wrong without feedback
Picture a projector controlled by infrared. The program sends "power on" and then assumes the projector is on, because that is the only thing it can do. From that moment the program's belief and the real world are two separate things that happen to agree.
Now let reality interfere, which it will. Somebody picks up the projector's own remote and turns it off; the program still believes it is on, so the panel shows a lit button and pressing it sends "power off" to a projector that is already off. Or the infrared command is missed because somebody is standing in front of the emitter, so the program believes the projector is on and it is dark. Or the room loses power overnight; the projector comes back off, the program comes back believing whatever it was told to believe, and the first user of the day finds a panel that disagrees with the room.
Each of these produces the same user experience, which is the most damaging one in this trade: the panel is lying, so the user stops trusting it, and from then on they press everything twice and call somebody. A room people do not trust is a failed room even when the equipment is perfect.
Feedback dissolves all of it. A projector the program can query is a projector whose real state the program knows: the panel shows what is true, somebody using the remote is noticed and accommodated, a missed command is detected and can be resent, and a power cut is recovered from by asking rather than assuming.
Which is why the rule from the chapter on the five ways to control a device — choose the method that gives you feedback — is not a preference. It is the difference between a room that works and a room that mostly works.
Polling, unsolicited feedback, and state
There are two ways to know a device's state and most systems use both.
Polling means asking, repeatedly. The program sends a status query every few seconds and updates its belief from the answer. It is simple, it works with any device that can answer a query, and it costs a little traffic and a little latency — you learn about a change up to one poll interval after it happens. Poll intervals are a judgement: too slow and the panel lags reality, too fast and you flood a device that was never designed for it. A few seconds is usually right, and some devices will fall over if you poll faster than they like.
Unsolicited feedback means the device tells you when something changes, without being asked. It is immediate and cheap, and it requires the device to support it. Some protocols define this explicitly, with a notification mechanism separate from ordinary commands, and where it exists it is better than polling. Most programs that use it still poll slowly as a safety net, because a notification you missed is indistinguishable from nothing happening.
Either way, the program needs one place that holds what it believes — a single source of truth per device, updated only from feedback and never from a command the program sent. That last clause is the whole discipline. The moment a program updates its belief because it sent a command rather than because the device confirmed, it has gone back to guessing, and the drift starts again.
Then everything else reads from that one place. The panel's feedback comes from it, the logic's decisions come from it, and a query that contradicts it corrects it. A program with two ideas of whether the projector is on will eventually show both at once, and that fault is extremely hard to find because the program is behaving exactly as written.
Devices that cannot answer
Sometimes feedback is impossible and the room still has to work. The honest approach is to make the guess as small and as visible as you can.
Use discrete commands rather than toggles wherever the device has them, so that a repeated command is harmless and the state cannot invert. Send the command more than once where that is safe, because with no acknowledgement the only defence against a missed command is repetition. Give the panel a startup routine that puts the room into a known state rather than inheriting a belief from yesterday. And where a sense input exists — a relay contact that closes when a screen is down, a current sensor on a projector — use it, because a primitive feedback signal is worth far more than none.
And be honest on the panel. A button for a device whose state is not known should not look like a button for one whose state is known. Showing a confident indicator for a guess is what teaches users that the panel lies.
How to do it
- For every device, establish whether it can report state and how.
- Where it can, decide between polling and unsolicited notification, and pick a poll interval.
- Create one place per device that holds the program's belief about it.
- Update that place only from device feedback, never from a command you sent.
- Point the panel's indicators and the logic's decisions at that place.
- On startup, query every device rather than assuming anything.
- For devices that cannot answer, use discrete commands and a startup routine.
- Make a guessed state look different on the panel from a known one.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| The panel disagrees with the room | State updated from commands sent rather than from device feedback | The single rule of this chapter; believe the device, not yourself |
| Users press every button twice | They have learned the panel is not trustworthy | Honest feedback; this behaviour never recovers on its own |
| Everything is wrong the first time the room is used each day | Program inherited yesterday's belief instead of querying on startup | Query every device at startup |
| A device stops responding when the system is busy | Polled faster than it can cope with | Lengthen the poll interval; some devices are fragile about this |
| The panel shows two states for one device | Two places in the program hold a belief about it | One source of truth per device, read by everything else |
| An infrared-controlled device ends up inverted | Toggle commands and a missed transmission | Discrete commands, repeated, plus a startup routine |
Practice it
On any control system you can inspect.
- Every device that can report state does.
- There is one place per device holding the program's belief.
- That place is updated only from device feedback.
- The panel and the logic both read from it.
- Every device is queried at startup.
- Guessed states look different on the panel from known ones.
Logic — Signals, Blocks and State
Every control platform expresses the same small set of ideas. Learn the ideas and a new tool is a matter of syntax; learn only one tool's syntax and a new platform is a new career.
A control program is logic the processor runs and an interface the user touches.
Signals and blocks
A control program is built from named values — signals — and things that transform them. There are three kinds of signal and they cover everything.
Digital signals are on or off: a button pressed, a device on, an interlock engaged. Most of a room program is digital.
Analog signals are numbers: a volume level, a lamp hour count, a selected input number. The word is historical and slightly unfortunate; they are integers.
Serial signals are text: a device's name, a message to display, a command to send. Again the word is historical — these are strings, and they have nothing to do with serial ports.
Logic blocks take signals in and produce signals out. The common ones are the familiar gates — and, or, not — plus comparison, arithmetic, buffers that pass a value when told to, and delays. Platforms differ in what they call these and whether you draw them or type them, and not at all in what they do.
The useful mental model is that a program is a graph rather than a sequence: signals flow, blocks react, and many things happen at once. Programmers arriving from conventional software find this the real adjustment — there is no single thread of execution to follow, and asking "what runs next" is usually the wrong question. Asking "what changes when this signal goes high" is the right one.
Interlocks, toggles and sequences
Three constructs cover most of what a room program does.
An interlock is a group of states where exactly one is active at a time. Source selection is an interlock: pressing "Laptop" selects it and deselects everything else, automatically, because the construct guarantees it. Almost every "two sources are both lit" fault is an interlock that was built as separate toggles.
A toggle flips a state each time it is triggered. Useful for things with exactly two states and no feedback — a mute button, a screen up or down. Dangerous everywhere else, for the reason the feedback chapter gives: a missed trigger inverts the state and nothing notices. Prefer discrete set and clear over a toggle whenever both exist.
A sequence is a series of actions with timing between them: the room-on macro that powers the projector, waits for it, lowers the screen, selects the source, and brings audio up. Sequences are where timing bugs live and they deserve their own section.
One more worth naming: the startup state. A program needs a defined behaviour on boot — query everything, assume nothing, put the room into a known condition — and a surprising number of programs simply do not have one, which is why they misbehave after a power cut.
Timing, and the device that lies
A device accepts a command and is not ready. That one sentence explains most sequence bugs in this discipline.
A projector acknowledges "power on" immediately and cannot accept an input-switch command for thirty seconds. A display reports itself on while its HDMI inputs are still negotiating. A switcher accepts a route before its output has settled. In each case the command succeeded and the device was lying about being ready, not out of malice but because "accepted" and "ready" are different states and most protocols only report the first.
The crude fix is a fixed delay, and it is how most programs are written: wait thirty seconds, then switch the input. It works and it is unsatisfying, because the delay has to be long enough for the slowest case, which makes the room slow for everybody, and it is still a guess.
The better fix, where the device allows it, is to wait for a condition rather than a duration. Poll the device's power status until it reports fully on, then proceed. Where a protocol has a distinct busy response — right command, wrong moment — that response is the signal to wait and retry, and a program built around it is both faster in the good case and correct in the slow case.
And give every wait a limit. A sequence that waits forever for a device that will never answer is a room that hangs, with no explanation offered to anybody. Wait, retry a sensible number of times, then report a failure that a human can see.
How to do it
- List the actions in the order they must happen.
- For each, establish what must be true before it can succeed.
- Where the device can report that condition, wait for the condition.
- Where it cannot, use a delay sized for the slowest realistic case and say so in a comment.
- Treat a busy response as a wait-and-retry rather than a failure.
- Give every wait a retry limit and a timeout.
- On timeout, report something a human can see rather than failing silently.
- Test the sequence from cold, from warm, and with one device unplugged.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| Input switch is ignored when the room starts from cold | Projector accepted power-on and was not ready for the next command | Wait for the condition rather than a duration, or size the delay for cold start |
| Two sources both show as selected | Built as separate toggles rather than as an interlock | Use the interlock construct; it guarantees exactly one |
| A mute button gets out of step with reality | A toggle and a missed trigger | Discrete set and clear wherever the device offers both |
| The room hangs during startup and says nothing | A wait with no timeout, on a device that will never answer | Every wait needs a limit and a visible failure |
| The room is reliable but feels slow | Fixed delays sized for the worst case | Wait on conditions where the device supports it; it is faster and more correct |
| Misbehaves only after a power cut | No defined startup state | Query everything on boot and assume nothing |
Practice it
On a room program you can read, or on paper.
- Mutually exclusive states use an interlock, not toggles.
- Toggles are used only where no discrete command exists.
- Every sequence step knows what must be true before it.
- Conditions are waited on rather than durations, where the device allows.
- Every wait has a retry limit and a timeout.
- A timeout produces a failure somebody can see.
- There is a defined startup state that queries rather than assumes.
The User Interface as a Design Problem
A correct program behind a confusing panel is a failed job, and it will be judged as one. The interface is not decoration applied at the end; it is the product, and it has rules.
Fewer decisions, not more features
Start from what somebody came into the room to do. In the great majority of rooms that is two or three things: show what is on my laptop, make a call, or play something. Everything else on the panel is there for the programmer's convenience or because somebody asked for it in a meeting.
So the first page should offer those two or three things and nothing else, as large, obvious, unambiguous targets. Everything the room can also do goes behind a clearly labelled way in — a settings page, an advanced page, a technician's page — and the test of whether something belongs on the first page is whether a visitor who has never been in the room would need it in their first ten seconds.
Then: one way to do each thing. A panel that offers two routes to the same outcome has doubled the user's decision and your testing. And label in the user's words rather than the system's. The user does not know what the switcher is called or which output number feeds the main screen; they know "the big screen" and "my laptop".
A genuinely useful discipline: write the labels before you build the pages, as a flat list, and read them aloud. Labels that sound like equipment are the ones to change.
A button must show its state
The single most common interface fault is a button that does not indicate anything. The user presses it, nothing visibly changes, and they press it again — which in a toggle-based design undoes what they just did, and in a sequence-based design starts the sequence twice.
Every control that has a state must show it, drawn from the program's belief, which is drawn from device feedback. A selected source is visibly selected. A projector that is on is visibly on. A mute that is engaged is visibly engaged.
And states that take time need a third appearance. A projector warming up is neither on nor off, and showing it as either is a lie that generates a support call: shown as off, the user presses again; shown as on, the user wonders why the screen is dark. A visible "starting up" state — with a progress indication if you can manage one — removes an entire category of complaint, and it is almost free because the program already knows.
Finally, show failure. When a device does not respond, the panel should say something human — not an error code, not nothing, but a sentence that tells the user whether to wait or to call somebody. A room that fails silently teaches people to distrust it; a room that says "the projector is not responding — please call reception" is still a working product in the only sense that matters.
How to do it
- Write down the two or three things people come to the room to do.
- Write all the labels as a flat list, in the user's words, and read them aloud.
- Put the two or three tasks on the first page and nothing else.
- Give every stateful control an on, an off and a transitional appearance.
- Point every indicator at the program's belief, which comes from device feedback.
- Decide what the panel says when a device does not respond, in plain language.
- Put everything else behind one clearly labelled way in.
- Test it with somebody who has never seen the room and watch where they hesitate.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| Users press buttons twice | The button does not show its state | Every stateful control indicates, from feedback |
| Support calls during the first minute of every meeting | No transitional state shown while a projector warms up | A visible starting-up state removes this entire category |
| Nobody uses most of the panel | Features exposed that nobody came to use | Two or three things on the first page; the rest behind one way in |
| Users ask which button is the screen | Labels in system vocabulary rather than the user's | Write the labels first and read them aloud |
| A failure produces a silent dead room | No failure state on the panel | Say something human and actionable |
Practice it
On any panel you can look at.
- The first page shows only what people came to do.
- Labels are in the user's words and were written before the pages.
- There is one way to do each thing.
- Every stateful control shows on, off and transitional.
- Indicators come from device feedback, not from commands sent.
- A non-responding device produces a plain-language message.
- Somebody unfamiliar has used it while you watched.
Writing a Program You Can Debug
You will debug this program in a year, under pressure, in a room full of people, having completely forgotten how it works. Every habit in this chapter exists to make that afternoon survivable.
Naming, structure and comments
Name signals so that reading one tells you what it is. A name should say the device, the thing, and for digitals the sense: not `d12` or `proj` but `Projector_Power_On_Fb`, where `Fb` marks it as feedback from the device rather than a command to it. That last distinction — command against feedback — is worth a naming convention of its own, because confusing them is how a program ends up believing itself instead of the device.
Group by device, not by function. All the projector's logic together, all the switcher's together. The alternative — all the power logic together, all the input logic together — looks tidy and makes a single device impossible to follow, which is exactly the task you will have at three in the afternoon when one projector is misbehaving.
Comment the why, not the what. A comment saying "turns the projector on" is worthless beside logic that visibly turns the projector on. A comment saying "thirty-second delay because this model accepts power-on and ignores input commands until the lamp is up" is worth an hour to whoever reads it next, including you. Every fixed delay in a program should have a comment of that kind, and most have none.
And keep a header block at the top of the program saying what room it is, what hardware it expects, what firmware it was built against, who wrote it, when, and what changed last. It costs two minutes and it is the first thing anybody inheriting the program will look for.
Simulating and testing before the room exists
A large part of a program can be proved at a desk, and almost nobody does it, which is why so much programming happens on site under time pressure with the client watching.
Most of what you can prove without the room: all the interface logic, since a panel can run on a computer; every interlock and sequence, since you can watch signals change; the shape of every command your drivers emit, since you can point a driver at a terminal on your own machine and read exactly what it sends; and the whole startup behaviour.
Pointing a driver at a terminal rather than a device is the trick worth taking from this chapter. You see the exact bytes, you can compare them against the protocol document character by character, and you find the wrong terminator or the missing space at a desk instead of in a room. Half of all driver faults are visible this way.
What you cannot prove without hardware: whether a real device accepts what you send, how long it actually takes, and what it says when it is unhappy. Which is why the devices should be on a bench before they are in a ceiling, and why a bench with one of each device is the most valuable thing a control programmer can be given.
Debugging on a live system
When you must work on a running system, the tools are the same everywhere even if the names differ: a way to watch signals change in real time, a way to see exactly what is being sent and received on each port or socket, and the processor's log.
The order is the six-stage flow from the earlier chapter. Is the button arriving as a control signal? Is the logic producing the output you expect? Is the driver emitting the bytes you expect? Is anything coming back? Each of those is observable, and the answer to one of them is where the fault is. Guessing in this discipline is unusually expensive because there are so many layers to guess among.
Three disciplines for live work. Change one thing at a time and write down what you changed, because a control program is easy to make worse quickly. Keep the working program, so that you can always put the room back — a copy of the compiled program and the source as they were this morning takes seconds to save and has rescued countless afternoons. And remember that connecting your terminal to a single-session device locks out the control system, which produces a fault that looks alarming and is entirely your own.
Finally, when you find it, write it in the notebook. The device that needs a second command after warm-up, the one that ignores commands for a moment after an input change, the one that needs DTR asserted — these are not in any manual and they come back on the next job.
How to do it
- Write a header block before any logic, naming room, hardware, firmware and date.
- Adopt a naming convention that distinguishes commands from feedback.
- Group all logic by device.
- Comment every fixed delay with the reason it exists.
- Point each driver at a terminal and verify the exact bytes against the protocol document.
- Prove all interface logic and every sequence at a desk.
- Keep a copy of the working program and source before changing anything on site.
- Record every device quirk you discover, in the notebook and in a comment.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| A program is unmaintainable a year later | Names that say nothing and no comments explaining the delays | The habits above cost minutes each and are the whole difference |
| Following one device's behaviour means reading the whole program | Grouped by function instead of by device | Group by device; it matches how faults arrive |
| Driver faults found on site under pressure | Bytes never verified against the protocol document at a desk | Point the driver at a terminal; half of driver faults are visible that way |
| The room is worse after an hour of debugging | Several changes made without records or a saved starting point | One change at a time, written down, with this morning's program kept |
| Control system stops working the moment you start debugging | Your terminal has taken the device's only session | Disconnect it; this fault is self-inflicted and extremely common |
Practice it
On any program you have or can read.
- A header block names room, hardware, firmware, author and date.
- Names distinguish commands from feedback.
- Logic is grouped by device.
- Every fixed delay has a comment saying why.
- Driver output was verified byte by byte at a desk.
- A copy of the last working program and source exists.
- Device quirks are recorded where somebody will find them.
Commissioning a Control System
Commissioning a control system means proving every device, every control and every path, in an order that makes a fault attributable. Done properly it is slow and dull and it is the difference between a handover and a series of return visits.
The order
Devices first, outside the program. Before the control system is involved at all, prove that every device responds. Use a laptop on the serial port, or a terminal to the address. Send one documented command and get the documented response back. Record the response for each. This stage finds cables, settings, addresses, credentials and firmware problems while they are still cheap, and it means every later fault belongs to the program.
Then each device through the program, one at a time. One device, one command, from the program. Then its feedback: change the device by its own controls and confirm the program notices. That second half is the one people skip and it is the one that proves feedback works.
Then every control on the panel. Every button, every slider, every page. Not the three you have been using — every one, including the ones on the technician's page, because those are the ones nobody will test again until they are needed in an emergency.
Then every sequence, from every starting state. Room on from cold. Room on when it is already on. Room off from on, and from off. Source change between every pair of sources. This combinatorial stage is where the real bugs are, because programs are usually written and tested from one starting state.
Then the failure cases. Unplug a device and see what the program and the panel do. Power the whole system down and up and see whether it recovers. Use a device's own remote mid-session and see whether the program notices. Those three tests find more problems than everything before them, and they are almost never run.
What to record
Commissioning produces a document, and it is short. For each device: the control method, the settings or address and port, the command you proved it with and the response you got. For the program: which sequences were tested from which starting states. For the failure cases: what happened for each one, including anything you decided to accept.
That last part matters. There is always something — a device that cannot report state, a projector that takes ninety seconds, a feature the client asked for that the equipment cannot do. Writing those down as accepted limitations turns them from faults somebody will report into decisions somebody agreed to, and it is the difference between a snagging list and a handover.
How to do it
- Prove every device outside the program and record its response.
- Prove each device through the program, one at a time.
- Change each device by its own controls and confirm the program notices.
- Operate every control on every page, including the technician's pages.
- Run every sequence from every realistic starting state.
- Unplug a device and record what the program and panel do.
- Power the whole system down and up and confirm it recovers.
- Write the commissioning record, including the accepted limitations.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| Commissioning passes and the first real meeting fails | Tested from one starting state only | Every sequence from every starting state; this is where the bugs are |
| Feedback was never actually tested | Only commands were tested, never the device changing on its own | Change each device by its own controls and watch the program |
| A fault on the technician's page during an emergency | Those controls were never tested | Every control on every page, once, properly |
| System does not recover from a power cut | The power-cycle test was never run | Run it; it is one of the three tests that find the most |
| Handover becomes a snagging list | Known limitations were not recorded and agreed | Write them down as accepted decisions during commissioning |
Practice it
On the next system you commission or can study.
- Every device was proved outside the program first, with its response recorded.
- Every device was proved through the program, including its feedback.
- Every control on every page has been operated.
- Every sequence was run from every realistic starting state.
- A device was unplugged and the behaviour recorded.
- The system was power-cycled and recovered.
- The commissioning record exists, with accepted limitations.
Handover and the Next Programmer
Two handovers happen at the end of a control job and most people do only one. The users need to be able to run the room. The next programmer needs to be able to change it. They want completely different documents.
Handing over to the people in the room
The room is judged by whether the people in it can use it, so this handover is the one the client actually experiences.
Do it in person, in the room, with the system live. Show the two or three things people came to do and let somebody else do each one while you watch — the watching is the valuable part, because it reveals the places your layout is not obvious. Show what happens when something goes wrong and who to call. Then leave one page, laminated or on the wall, with the two or three tasks and the phone number. Not a manual; a page.
Keep it short and resist the temptation to demonstrate everything the system can do. The person being trained will remember three things, and you get to choose which three.
Handing over to whoever comes next
Somebody will change this program, probably not you, probably in a hurry, probably when you are unreachable. What they need is a small pack and none of it is difficult.
| What to leave | Why they cannot work it out otherwise |
|---|---|
| The program source | Without it the room can never be modified by anybody |
| The compiled program as loaded | So a replacement processor can be restored rather than rebuilt |
| The panel layout files | They are separate from the program and are needed to change a button |
| A device table | Method, settings or address and port, and credentials location, per device |
| The commissioning record | What was proved, and what response each device gave |
| The accepted limitations | Otherwise they read as faults, which is unfair to everybody |
| The device quirks list | Not in any manual, and the thing that will cost them a day |
| Firmware versions | A program may not load onto different firmware |
Credentials go where the organisation controls them rather than in the pack or in a comment. Note in the pack where they live.
And put the whole pack somewhere the organisation owns — not only on your laptop and not only in your email. The commonest failure in this discipline is not a bad program; it is a perfectly good program whose source nobody can find.
How to do it
- Train the users in the room, on the live system, letting them do each task.
- Leave one page with the two or three tasks and a phone number.
- Collect the program source, the compiled program and the panel layouts.
- Write the device table with method, settings or address, and where credentials live.
- Add the commissioning record, the accepted limitations and the quirks list.
- Record every firmware version.
- Put the pack somewhere the organisation controls, and tell them where.
- Keep your own copy.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| The room cannot be modified by anybody, ever | Program source lost | The single most common and most expensive failure in this discipline |
| A replacement processor means rebuilding the program | No copy of the compiled program as loaded | Keep it with the source; restoring takes minutes, rebuilding takes days |
| A button cannot be changed | Panel layout files missing — they are separate from the program | Include them in the pack |
| The next programmer spends a day rediscovering a device quirk | The quirks list was never written | It is the least formal document in the pack and often the most useful |
| Users cannot run the room a week after handover | Trained by demonstration rather than by letting them do it | Let them do each task while you watch and say nothing |
Practice it
For a room you have worked on.
- Users were trained in the room and did each task themselves.
- A one-page user sheet is in the room.
- Source, compiled program and panel layouts are all kept.
- The device table exists, with where credentials live.
- The commissioning record and accepted limitations are included.
- The device quirks list is written down.
- Firmware versions are recorded.
- The pack is somewhere the organisation controls.
Building, Testing & Certification
The building and testing loop is short and it is worth having as a habit rather than a procedure. Certification, in this discipline, genuinely gates work — which is unusual in AV and worth being clear about.
A control program is built methodically, tested on real gear, and mastered through certification.
Building and testing a program
The loop is: change one thing, compile, load, test that one thing, and keep or revert. That is it, and the discipline is in the word "one". A control program compiles quickly and loads quickly, so there is no efficiency argument for batching changes — only the temptation to feel productive, which is paid for with an hour of not knowing which change broke it.
Keep the last working build. Before every load, you should be able to put the room back to how it was, in under a minute, without thinking. On a live system this is not optional.
Test the thing you changed and then one thing around it, because control programs have more coupling than they look like they do — a change to a source-selection interlock can affect the room-off sequence that reads from it. The combinatorial testing from the commissioning chapter is the full version of this; during development the cheap version is "and now check the sequence that uses this".
And test from cold occasionally. Programs are developed on a system that has been running all day, and the behaviour that matters most — the first use of the morning — is the one least often exercised.
The path to certification
Control programming is the corner of AV where manufacturer certification genuinely decides what work you can do. Several manufacturers restrict their programming software, their device modules, or their dealer support to certified programmers, which means certification is not a credential that looks good but a gate you pass through to be allowed to work at all. That is worth knowing early because it changes how you plan.
The usual shape is a sequence: an introductory course that gets you into the tools, one or more intermediate courses on the programming language and the hardware, and a certification that is examined. They are vendor-run, they are not free, and employers very often pay — which is the practical route in, and a reason to get a job with an integrator before trying to self-fund.
What transfers and what does not is worth being honest about. The ideas in this book transfer completely: feedback, state, interlocks, sequences, protocols, debugging, handover. Those are the same on every platform and they are what makes somebody a programmer rather than a tool operator. The syntax, the development environment and the module libraries do not transfer, and learning a second platform is a few weeks rather than a few years for anybody who holds the ideas.
So the advice is to get certified on whatever platform the work near you uses, and to keep the ideas separate in your head from the tool. Programmers who have only ever known one environment struggle when the market moves; ones who understand what the environment is for do not.
Alongside the vendor path, two things are worth doing. Learn enough general programming to write a driver from a protocol document, since most platforms allow a text-based module and that is where the interesting work is. And read protocol specifications for fun, because the skill that distinguishes a senior control programmer is being handed an undocumented device and getting it working anyway.
How to do it
- Save the last working program and source so the room can be restored in under a minute.
- Change exactly one thing.
- Compile and load.
- Test the thing you changed.
- Test one thing that reads from or depends on it.
- Keep it, or revert and write down what you learned.
- Occasionally test the whole room from cold.
What goes wrong
| Symptom | Likely cause | What to do |
|---|---|---|
| An hour lost to not knowing which change broke it | Several changes batched into one load | One change per load; compiling is fast and your time is not |
| A change broke something apparently unrelated | Coupling through a shared state or interlock | Always test one thing that depends on what you changed |
| Works all day and fails first thing in the morning | Never tested from cold | Test from cold occasionally; it is the case that matters most |
| Cannot put the room back | No saved working build | Save before every load; on a live system this is not optional |
Practice it
On your own development habits.
- The last working build is always restorable in under a minute.
- Loads contain one change each.
- Each change is tested along with something that depends on it.
- The room gets tested from cold from time to time.
- You know which certification the work near you requires.
- You can tell the ideas apart from the tool that expresses them.
Where to Go Next
Control programming sits at the centre of a lot of other work, which makes it a good place to have been. Networking Basics and AV Networking Intermediate are the obvious next step, because almost every device you will control arrives on a network and most control faults that are not programs are reachability. Sideways, the audio and video courses tell you what the devices you are commanding actually do, which makes you better at commanding them.
The first ninety days
Get a bench with one device of each kind on it and a processor, and write a program for a room that does not exist. Then break it on purpose: unplug a device, change one by its own remote, power-cycle everything, and make the program cope with each. That is the whole skill, compressed.
Start the notebook on day one — device, method, settings, the command that turns it on, what it says back, and the thing that surprised you. Two years of that is what separates somebody fast from somebody competent, and it cannot be acquired any other way.
And read one protocol specification end to end, properly, the way this book reads PJLink. After that, an undocumented device is a puzzle rather than a wall, and being the person who gets undocumented devices working is a reliable way to be the person who gets asked.
Where this leads
Control programmer, then systems programmer across whole buildings, then the design and integration roles where somebody owns how a room behaves rather than what is in it. Certification gates the early part of that path and employers generally pay for it, which is the practical argument for starting with an integrator.
Glossary
| Control system | A processor running a program that makes separate equipment behave like one appliance |
| Processor | The small computer that runs the program; it boots, logs, and can be inspected while running |
| Touch panel | A networked screen the program draws on and reads presses from, with its own layout file |
| Keypad | A button panel with no display, so it can show state only through backlighting |
| Control signal | A named value inside the program — not an audio or video signal |
| Digital signal | A control signal that is on or off |
| Analog signal | A control signal carrying a number, such as a volume level |
| Serial signal | A control signal carrying text; nothing to do with a serial port |
| Logic block | Something that transforms control signals — a gate, a comparison, a buffer, a delay |
| Driver or module | Reusable logic that turns program outputs into the bytes one device expects |
| Join number | The number that connects a panel control to a point in the program |
| Interlock | A group of states where exactly one is active at a time, guaranteed by the construct |
| Toggle | A construct that flips a state on each trigger; dangerous without feedback |
| Sequence | A series of actions with timing between them, such as a room-on macro |
| Startup state | What the program does on boot; it should query every device rather than assume |
| Feedback | Either a device reporting its state to the program, or the program telling a panel what to light |
| Polling | Asking a device for its state repeatedly, on an interval |
| Unsolicited feedback | A device reporting a change without being asked |
| Source of truth | The one place in the program holding its belief about a device, updated only from feedback |
| Discrete command | A command that sets a definite state, such as power-on, rather than flipping it |
| Contact closure | Control by closing a pair of relay contacts; one-way unless a sense input exists |
| Infrared | Control by emitting the codes a remote sends; one-way with no acknowledgement at all |
| Baud rate | Serial speed in bits per second; one of the four settings that must match |
| Parity | A serial error-check bit, usually none |
| Null modem | A crossed serial cable; a device given the wrong type is silent |
| DTR | A serial control line some devices require asserted before they will respond |
| BREAK | A deliberate serial line disturbance a few devices use as reset or attention |
| Device server | A box that puts a serial device on the network; a cheap one may not carry control lines |
| Telnet | A session protocol many devices offer for control; it negotiates options in the data stream |
| Line ending | Carriage return, line feed, or both — a common reason a correct command is ignored |
| PJLink | A manufacturer-neutral protocol for controlling projectors and displays |
| Busy response | A device saying the command was right and the moment was wrong; wait and retry |
What the gear actually looks like
Every device named in this book, in one place. Recognition is the whole point of Chapter 4 — use this page to attach a picture to each name before you meet it on a dock at six in the morning.
Find the destination.
Work along the path between them.