Project overview
The Four-Channel Magnetic Lock is a controller for four electromagnetic holding points with a countdown timer and an MQTT interface. Each channel consists of a magnet in a printed pot and a steel anchor with an eye bolt; energising the magnet holds the anchor, cutting the current releases it.
It was built as a module for a larger training system that has been in development since 2022. The work is a collaboration with an international manufacturer of BDSM equipment, who is not named here: they sponsor that system’s development and are a co-organiser of the museum project it is being built for. The countdown is the part that makes it more than a switch: the module gives a set time for all points to be connected, watches the presence contacts, and reports back over MQTT whether that happened. Because the holding is purely electrical, the same module works for remote operation and for unattended use, where no second person is present to open anything by hand.
This page documents a prototype. The hardware is built and working; the failure handling in the firmware is still open work, the module is not in regular use, and it is not for sale.
What is here and what is not. The training system this module serves was published by Philine Graystone in September 2026. That project is not part of this site and is not documented here: it is an engineering system, and it is also an installation about consent, control and the psyche, and the second half is a conversation for a museum rather than for a STEM portfolio. What belongs here is this module — the electronics, the mechanics, and the reasoning behind both.
The module itself stays where it is. There are no files here — no housings, panels or anchor stack, no board files, nothing to download — and this page is a description, not a set of instructions for building something that holds a person. What a collaboration opens up, and when, is also not one side’s decision to take alone. That one has not been taken.
Electronics and control
An ESP32-S3 runs the module, with a Waveshare LCD1602 RGB as the status display. The backlight colour carries the state, so the condition of the module is readable across a room without reading the text.
Each channel leaves the enclosure through one six-pin circular connector carrying six lines: 12 V and GND for the magnet, 5 V and GND for the sensing, and two separate presence signals. The two presence lines are the part worth explaining, because they answer different questions:
| Signal | Question it answers |
|---|---|
| Plug present | Is a magnet unit connected to this channel at all? |
| Contact closed | Is a puck lying in that pot? |
A channel with nothing plugged in is a different state from a channel that is plugged in but open, and the module needs to tell them apart before it starts a countdown against a point that does not exist.
Note what the second line does not say. The switch reports a puck lying in the pot, nothing more: laid into a pot whose magnet is dead, it presses the same lever as one the magnet is pulling down hard. The module therefore cannot tell a held point from a merely occupied one, which means it cannot report a channel as stuck — as still holding something it believes it has released — and it deliberately does not try. A status built on a signal that cannot answer the question is worse than an admitted gap, because it is believed.
Switching is done by one Heschen JQC-3F(T73) relay per channel between the supply and the magnet. The supply itself sits outside the enclosure and comes in through its own connector, so the only thing inside the housing is low voltage and the switched 12 V.
The release path is deliberately passive. The magnets hold only while current flows, so interrupting the supply — pulling the inlet, switching off the external supply, a power cut — drops all four channels at once with no software involved.
Mechanical construction
The magnet pots and the panels are printed in PC-CF on a Qidi X-Max 3. The material was chosen for one reason: an electromagnet energised for an extended period inside a closed pot gets hot, and a housing that softens around a magnet under load is not an acceptable failure. PC-CF holds its shape at temperatures where the more convenient materials do not.
The first pots were printed in PA12-CF, which is the more comfortable material to work with and holds up well enough for most things. It is not the one to build these out of — PC-CF simply takes more heat, and in the one place on this module where that matters, more is the only argument that counts.
Each pot takes the magnet with its face flush at the opening, a cable channel through the wall, and a microswitch with its lever lying inside the pot: laying the puck in presses the lever down, and that is the seating signal.
The anchor itself — the puck — is a short stack rather than a single part. Three steel washers at the bottom, which are what meets the magnet face, two printed PC-CF discs on top of them, and the eye bolt through the middle. The plastic is a heat shield, and it sits where it does for a reason: steel conducts, the magnet runs warm, and in an all-steel stack that heat arrives at the top of the puck, which is the end everything else clips to. Keeping the hot half at the bottom is the whole trick.
The control enclosure carries all five connectors on one end panel, with screw caps on the unused channels.
Software
The module subscribes per device UUID and reports its state back on its own topics, including a periodic ping so the controlling system can see that it is alive. Commands set the timer and arm the channels; the module answers with the presence state of each point and with a release confirmation when the countdown reaches zero.
The countdown drives the display directly and, at zero, sets the relays back to the released state.
None of that is invented here. The module speaks the training system’s device contract, the same one every device in that system speaks: an identity derived per unit, signed commands, and a last will that tells the central unit when a device has gone quiet. Writing a module means implementing that contract, not inventing a protocol for one box.
Two timers sit underneath all of it and decide what happens when the conversation stops: one for a controller that has gone silent while a channel is held, one for a broker that is gone altogether. Both are set to 120 seconds, and that number was argued over — see the lessons below.
Lessons learned
Size the magnets for the worst case, not the expected load. Each channel holds 80 kg, which is far above anything a single wrist or ankle point sees — these are restraints on an upright frame, nothing hangs from them. That is intentional. A magnet chosen to just about hold will let go under a sudden hard pull, and something that releases unpredictably under load is more dangerous than something that holds reliably. The margin is not there to carry more weight; it is there so that the release happens when the controller decides it does, and not when the mechanics give up.
Heat leaves an energised coil by more than one path, and each needs its own answer. The obvious one is the pot: sealed around the magnet, warm for as long as the channel is held, which rules out most of the convenient print materials and led to PC-CF. The less obvious one runs the other way, through the steel of the anchor and into whatever is attached to it. Two printed discs on top of that steel keep it off the attachment end. Solving only the first would have produced a housing that survives perfectly while conducting the problem straight to the person.
“Fail safe” has no single direction — it has to be decided per failure, and written down. Two things can go wrong here that sound alike and want opposite answers. A command that does not verify — wrong signature, wrong shape, expired — must change nothing: the module stays as it is. A controller that has fallen silent while a channel is held must eventually release. The first was a real defect once: the check path fell through as allowed when it errored, which for a lock means a malformed message could open it. It now fails closed.
The second is the more interesting half. The timeout started at three seconds, which sounds responsible and was wrong: the installation runs on 2.4 GHz in a public room, brief dropouts are normal, and three seconds meant a Wi-Fi hiccup dropping someone’s restraints. It is 120 seconds now, and that number is only defensible because of what sits beside it — a supervisor in the room and an emergency-stop bumper that cuts mains power without asking the software. The timeout is not the safety measure. It is what happens after the safety measure has already been available for two minutes.
A confirmation is a message about a message. The module reports that it has released; what actually matters is that the relay opened and the presence contact went open with it. The same lesson turned up on the software side of the project, more sharply: a log line saying a value had been capped, while the uncapped value went out on the air. That version is the dangerous one, because it looks correct in every view a person would think to check. Since then the rule is to verify the effect at the far end — what the device received, what actually came out — and never the intention at the near end.
A check that cannot fail is worse than no check, because it reports success. Three of this project’s bench tests printed their findings and always returned zero; one of them had been calling a database record by a number that does not exist in a fresh installation, so half of it had been testing the age of the database rather than the equipment — and saying “passed” while doing it. A second case: the build refuses placeholder credentials, but the first version compared against the literal placeholder text, so an empty key sailed through. A guard has to catch the class of mistake, not the example you had in mind when you wrote it.
What you publish, what you keep, and who does the publishing are three separate decisions — and in a collaboration not one of them is a single side’s to take. Code can be read, checked and argued with, which is a good reason to put it out. The printed parts are the half that turns a description into a working restraint, which is a good reason not to. And whoever releases a thing is the one answering for it afterwards, which is a question of its own rather than a consequence of the other two. It is tempting to treat all three as one and settle them with a single checkbox. Here they have different answers, and they were not all mine to give.










