GeistHaus
log in · sign up

https://blog.jfedor.org/feeds/posts/default

atom
25 posts
Polling state
Status active
Last polled May 18, 2026 18:39 UTC
Next poll May 19, 2026 16:44 UTC
Poll interval 86400s
ETag W/"cc7cd91c057dd78386ad577a249d914acbde0b2cf08b84ed519ae17be4232308"
Last-Modified Thu, 23 Apr 2026 22:52:20 GMT

Posts

ByoWave Proteus controller
Show full content

On paper, the ByoWave Proteus controller sounds like a perfect setup for a failed Kickstarter. A small team makes an attempt at a very ambitious first product, fails to deliver at all or delivers some severely cut down version of it after years of delay. Except in this case there was no Kickstarter and they didn't fail. This post is a random collection of thoughts and facts about the controller, presented in the hope that it might be useful to someone trying to decide if it's the right solution for them. All my experiences are with the as-of-now-current V2 edition of the controller.

You probably already know what it is if you're reading this, but let's start with a quick recap of the premise. The ByoWave Proteus controller is a modular game controller with a strong focus on accessibility. The idea is that you can build different controller shapes with it to match your individual needs. It consists of a number of rounded cubes that can be connected together, either directly or using additional spacer elements. There are two types of cubes: the power cube, which has a battery and is responsible for the wireless connection to your computer or console, and the analog stick cube, which looks the same except one face has an analog stick on it. Buttons and triggers are attached to the faces of the cubes. There's a four button attachment (ABXY and Xbox system buttons), a one button attachment, a d-pad attachment, a bumper/trigger attachment and a small analog stick attachment. It also comes with grip attachments that can be used for building traditional controller shapes.

The Proteus controller uses the Xbox One controller protocol (it is an officially licensed Xbox product) so out of the box it's compatible with Xbox One and Series consoles and Windows PCs. It also works on Linux if you have a recent enough (6.16+) kernel and it does work on the Steam Deck. It comes with a wireless dongle and the dongle is the only way it connects to the host. It does not have Bluetooth and it does not work wired (though it requires a wired USB connection to the PC for configuration, more on that below). You can use adapters to make it work with other consoles like the PS5, Switch or Switch 2.

The packaging it comes in is very nice and I'm definitely keeping it for storing modules that are currently not on my controler. The controller itself also just looks cool, which is perhaps not as important as whether it works well, but I think it's good that some effort went into it. Accessibility oriented controllers shouldn't have to look like hospital equipment. I like the snap-on covers with various playful designs.

It comes with two power cubes, which lets you use the kit to build two separate controllers (perhaps for a split configuration), but the wireless dongle can only talk to one controller at a time and the kit only comes with one wireless dongle, so to actually use it like that you'd have to buy an additional wireless dongle. Once you do you can use the "Assist" function on Xbox and Windows to make the two controllers work as one. I assume there's some technical reason why a single dongle can't talk to two power cubes simultaneously, but if would be really awesome if it could: split configurations make a lot of sense for a lot of people.

In addition to working as an Xbox controller ("GIP mode"), the controller can also emulate a mouse/keyboard combo ("HID mode"), which works on any platform that supports mice and keyboards. In this mode you can also define macros (strings of inputs) executed with a single button press.

The cubes and attachments come with default functions and you can build various configurations without ever having to use the configuration utility, just by disconnecting and reconnecting the modules to achieve different controller shapes. Which, by the way, you can do on the fly, without having to power down or disconnect the controller. But of course at some point you might want to change the default functions. This is done through a web application that connects to the controller over USB via the charging module. The charging module is just an attachment with a USB port and, as the name suggests, it's also used to charge the batteries inside the power cubes. Please note this USB connection is separate from the wireless dongle (which also plugs into a USB port of course). This means that when you're configuring your controller you might have both the dongle and another USB cable plugged into your PC. But this also means that you can plug the dongle into a different machine. So for example you can plug the dongle into your Xbox console while also having the controller connected to your PC using a USB cable. That way you can reconfigure it live and see the effects immediately in game.

The web based configuration utility uses WebHID to connect to the controller so it only works in the desktop version of Chrome (and possibly other Chrome-based browsers like Edge). Windows, Linux and Mac versions of Chrome are all fine. I love that this has now become the standard for configuring devices like this. Boo Firefox and Safari for not supporting WebHID.

Inside the configuration utility you can remap the buttons, sticks and triggers and switch between controller and keyboard/mouse modes. It shows a 3D view of your current controller shape and it updates live, which I think is a really nice touch. You can do most things you would expect, like change the "up" direction on the sticks, which is necessary given all the different ways you can put the modules together. Though there are still things that it lacks, for example even though it has a "shift" functionality, letting you assign a separate function to buttons when a certain button is held, this cannot be done in a "toggle" manner, enabling the shifted functions permanently without having to hold that button. ByoWave keeps adding new features so if there's some specific thing that you need for your setup, it's best to check as reviews written near the launch might not have all the current information.

The hardware itself seems robust, the modules connect securely and don't look like like they'll fall apart. But I haven't used it enough to speak about long-term durability.

I noticed that it takes 15+ seconds for the controller to connect to the wireless dongle once you turn it on. It's not a huge issue, but I'm used to other devices that connect immediately.

As I mentioned, the entire point of the controller is that you can build it in various shapes to suit your needs. An important aspect of that is that you don't have to use all the modules at all times. If the game you're playing only requires one analog stick and one or two buttons, you can build a configuration that only has those, that you can better use with one hand for example (in other words, it scales down nicely). That said, any given configuration you come up with will probably not be as good as a non-modular controller that was designed to have this shape from the start. If all you want to build is a PlayStation-controller-shaped controller then you're probably better of getting a PlayStation controller. Of couse, the whole point is that most shapes you can build with the Proteus are not available to buy off the shelf.

In addition to the modules the controller comes with, ByoWave designed and published files for 3D printable attachments for the controller. Using these files someone could conceivably design new shells or ways to connect the existing modules, making even more controller shapes possible. The caps on the analog sticks are also replaceable and there are some 3D printable designs for alternative caps fulfilling individual needs.

For example, I printed an attachment with an M6 thread insert and used the Proteus module as the balltop on an arcade stick lever.

Currently the Proteus controller is sold in two kits: one offers all the modules necessary to make a standard controller and the other only has a subset of the modules and comes with a one handed shell for a tabletop controller. It would be really good if the modules were available individually and I hope in the future ByoWave will let us pick and choose. Perhaps some more niche modules could be offered this way. There are signs that they're working on a motion (gyro) input module, which would be interesting (though likely hindered by the Xbox platform's lack of native support for it). I could also imagine button modules with various shapes and various actuation forces. Perhaps we could even have a module with one or more 3.5mm jacks that could be used to extend the setup with external buttons or switches, Xbox Adaptive Controller-style.

Speaking of the Xbox Adaptive Controller, the Proteus controller does not appear to work when the wireless dongle is plugged into the USB ports on the Xbox Adaptive Controller. This is somewhat weird because the XAC already knows how to talk to the Xbox Adaptive Joystick for example, which uses the same Xbox One controller protocol as the Proteus. So it would probably just be a matter of allowlisting some additional product IDs. This is not a huge issue because, as I mentioned, you can use the "Assist" function on Xbox and Windows to make two controllers work as one, so you can use it to combine the XAC and the Proteus controller into one. But if you're using the XAC as part of your Switch or PlayStation setup using adapters, or you're on Steam Deck, you don't have this option.

But on a related note, I'm happy to report that the Proteus controller works great with HID Remapper in both GIP (controller) and HID (keyboard/mouse) modes. You could make it compatible with the Nintendo Switch and Switch 2 this way or enhance its functionality beyond what the Proteus can do by itself. Indeed you could also use HID Remapper to make the Proteus controller compatible with the Xbox Adaptive Controller or use it to make two Proteus controllers work as one on non-Microsoft platforms.

On the Proteus controller, the controller and keyboard/mouse modes are mutually exclusive, the controller is either in GIP mode or HID mode. First party Xbox controllers like the Xbox Adaptive Controller and the Elite controllers can be configured to send keyboard inputs while working as a controller. I wonder if this is something that ByoWave could add to the Proteus controller in the future.

I haven't done any proper performance testing with the Proteus controller. In some informal tests I have never seen it send more than 50 reports per second. This probably has consequences for input latency. Ultimately you will have to decide whether this matters to you. I doubt it makes any difference in casual play. It might make a difference for pro players, but I don't think they're the target audience here anyway.

The biggest downside for me is the lack of native PS5 compatibility. I don't know the reasons for it and I don't know what it would take to make it possible. My guess is we would need a separate wireless dongle for the PS5, which I think a lot of people would be okay with if it meant not having to deal with adapters. But there might be some bigger non-technical obstacles.

I can't tell you if the ByoWave Proteus controller will be the right fit for you, but I hope I have provided some data that will help you make an informed decision. Thanks for reading.

tag:blogger.com,1999:blog-5743520447405866726.post-4496990279860610832
Extensions
2025 roundup
Show full content

Here's some stuff I did last year.

  • Pixelrings: LED earrings programmable in Python.
  • RP2040-RS232: RS-232 adapter with an RP2040 chip. Can be used to adapt ancient serial mice or 3D mice for modern systems or as a generic serial-to-USB adapter.
  • Some new Flatbox revisions:
    • rev4.1: an updated RP2040 variant with a USB host port
    • rev4.1wasd: same but with a WASD layout
    • rev8: an RP2350 variant with a USB host port
    • rev9: a SAMD21 variant
    • rev10: an STM32G0B1 variant
  • Portable Gamepad Firmware: a wired game controller firmware. Through the power of Zephyr the same code runs on many different platforms with the hardware details defined in devicetree overlays. Functionality is super basic right now, but we have builds for many different boards, including the Flatbox variants above. Does 8000 Hz on hardware that supports it (currently Teensy 4.0).
  • HID Remapper now has a proper website and a forum. Also builds for the RP2040/RP2350 Flatbox variants.
tag:blogger.com,1999:blog-5743520447405866726.post-2877280350642959441
Extensions
What I've been up to
Show full content

I used to post on this blog whenever I finished a project, but these days I typically just put it on GitHub and call it a day. I think some of these projects deserve separate posts, but just in case I never get around to it, here's what I've been doing for the last three years or so.

  • HID Remapper: programmable adapter for USB input devices. Remap buttons, make keyboards work as game controllers, make joysticks work as mice or vice versa. Lots of cool stuff, including accessibility applications.
  • Flatbox: this one got its own post, but I've made a few more variants since then, including a wireless one!
  • Trackballs: I made a PCB with an RP2040 chip and a PMW3360 mouse sensor that can be used to quickly prototype mice and trackballs. Then I made a few trackballs using it. Notable mentions: spherical trackball, two-ball trackball, trackball with twist-to-scroll, trackball with scroll ring.
  • Slimbox Generator: a website for rapid prototyping of leverless controller layouts. Generates 3D-printable files.
  • PlayStation Access Controller Profile Editor: a website for editing the button mapping on a PlayStation Access controller without a PS5.
  • HID Forwarder: a system for sending synthetic inputs from a PC to something like a Nintendo Switch, over serial, wifi or Bluetooth, with potential accessibility applications.
  • Slimbox BT: wireless game controller firmware for nRF52 chips.
  • Zero Latency Gamepad: lots of products claim low latency, mine actually comes very close to what's physically possible on Full Speed USB.
  • Latency tester: speaking of latency, I made my own latency tester for game controllers and other USB input devices because I wasn't happy with existing ones.
  • Spaceball 2003 USB adapter and Magellan/SpaceMouse USB adapter: these let you use ancient RS-232 3D mice with modern software.
  • Google Meet mute button: a physical button that lets you mute your microphone on a Google Meet call regardless of which window is active and has a nice LED indicator to show when you're on call and if the microphone is muted.
  • PS5 adapter for old Logitech wheels: play Gran Turismo 7 with the Logitech Driving Force Pro wheel from 2003. Possibly other old Logitech wheels.
  • RPM lights for Gran Turismo 7: use GT7 network telemetry to make pretty physical shift lights for your virtual car.
  • Screen Hopper: smart KVM switch that lets you just drag the cursor from one computer to another, no software required. A hack on top of HID Remapper.
tag:blogger.com,1999:blog-5743520447405866726.post-7666718184850253438
Extensions
DIY Surface Dial
3d printinghidrp2040
Show full content

Microsoft's Surface line of hardware has some nice computers and accessories. Among the accessories there's the Surface Dial - a Bluetooth knob that can do things like volume control, scrolling, undo/redo and some other functions in certain applications, mostly artist-oriented. For some reason the physical form of the Surface Dial appeals to me, but since its price is not exactly in the impulse buy territory and I don't have a practical need for it, I never got one. But now I have made my own version of it. It's not as nice as the real one and it's missing some of the functionality, but it really does work as a Surface Dial in the software that supports it.

There are two aspects to this device, making the physical hardware and programming it so that Windows recognizes it as a Surface Dial.

From the hardware perspective, we need two things - a way of detecting the dial's rotation and a button. On the real Surface Dial the entire knob works as a button, but in my version, there's a separate button in the middle, made using a mechanical keyboard switch. As for the dial itself, instead of using an off-the-shelf rotary encoder, I made my own using small neodymium magnets and two Hall effect sensors. Its principle of operation is the same as with other incremental encoders, the sensors are oriented so that their signals have a phase difference. In theory we could get better resolution by using the full resolution of the sensors' output, instead of treating them as binary, but I haven't done that. The resolution I got is determined by the number of magnets (48).

I designed the case for the device in Fusion 360 and 3D printed it. The dial sits on a 6806 ZZ bearing and has a very satisfying feel. Here's what it looked like during assembly.

For the microcontroller I chose the Adafruit QT Py RP2040, it's small and uses the RP2040 chip from Raspberry Pi (it has a similar form factor to Seeed Studio's XIAO RP2040).

Since we're talking about Microsoft, I half-expected the Surface Dial's protocol to be some proprietary nonsense that would require reverse engineering to replicate. Imagine my surprise when I found out that it's actually standard HID and there's proper documentation for it. All you have to do is put the right stuff in the HID report descriptor and it works similarly to a regular USB mouse or keyboard.

I put all the code and 3D-printable files on GitHub, along with a list of components used and instructions how to put them together.

tag:blogger.com,1999:blog-5743520447405866726.post-8168355694164539675
Extensions
Two mice, two cursors
arduinohidmouse
Show full content

I always thought that when you connect two mice to a computer, there should be two mouse cursors, one for each mouse. Unfortunately that's not really how it works on modern operating systems, at least not by default. Software add-ons exist that draw a second cursor for the second mouse (and also perform some tricks to make button clicks work as expected). I'm sure they work fine, but I came up with a pure hardware solution to the problem that requires no special software running on the host. Here's a video demonstrating this solution.

What you can see here is two mice, connected through a USB hub to an Arduino Leonardo with a USB Host Shield. The mice are wireless, but they use 2.4 GHz USB receivers so they're effectively USB devices. The Arduino is connected to the computer and acts as a USB mouse.

The Arduino reads inputs from the two mice, does its magic, and sends the resulting inputs to the computer. What's the trick that makes the computer display two cursors? If you look closely, you'll notice that the two cursors flicker a bit. That's because they're not really two cursors, instead it's just the one normal cursor oscillating quickly between two positions on the screen, appearing as two due to persistence of vision. The Arduino keeps track of the X/Y positions of both cursors and updates them based on the inputs received from each mouse. Then it alternates between the two causing the illusion of two cursors. To be able to do that it uses absolute cursor positioning, unlike a regular mouse, which only sends the X/Y deltas and doesn't know where on the screen the cursor is at any moment. (I have previously used absolute cursor positioning for both good and evil.)

One remaining problem is what to do when you click a button on one of the mice. The user will naturally expect for the click to happen at the screen position of the cursor corresponding to that mouse. So we can't keep alternating between the two cursors. For as long as the button is pressed, we only send the cursor position of the mouse that's doing the clicking. This means that the second cursor disappears for a brief moment, but the clicks work as expected.

If you want to play around with it, I posted the source code on GitHub. It uses the standard USB HID protocol and works with Windows, Linux and Mac, without any additional software needed on the computer.

tag:blogger.com,1999:blog-5743520447405866726.post-8049761347307339829
Extensions
Razer Raion padhack
3d printinghid
Show full content

One of the problems when making a custom fightstick (arcade controller for fighting games) is modern console compatibility. While it was easy to make an Arduino or similar board work as a USB controller for the PS3, unfortunately it is no longer the case with the PS4 and PS5. Only licensed controllers work with them due to restrictions introduced by Sony. Every licensed controller has a private key embedded in it that allows it to perform some kind of authentication when connected to a console. One solution to this problem is a practice known as padhacking: taking the insides of an existing licensed controller and transplanting them into a different enclosure, for example a fightstick-shaped one, carefully soldering wires between buttons and the right places on the donor PCB.

In theory you can use any controller for this, like a DualShock 4 or a DualSense, but it makes sense to choose one that will be relatively cheap to obtain and also easy to solder to. One such controller is the Razer Raion. It was originally released for the PS4, but since it qualifies as a "specialty peripheral", it also works in PS5 games. I got one and made a mixbox-layout fightstick using its PCB.

First I had to figure out where the solder points that I need are on the PCB. Fortunately I found this helpful tweet and with this information it was a fairly straightforward job.

The rest of the fightstick was similar to what I've done previously, in fact I just modified one of the designs to accomodate the Raion PCB. Here's what it looks like inside. As you can see it uses common ground.

One thing to keep in mind when converting a controller like this is the matter of SOCD cleaning - what happens when you press opposing direction buttons at the same time? Most traditional controllers don't have to worry about this because it's physically impossible to simultanously trigger opposing directions on them. But when you make a stick that has separate buttons for up, down, left and right, that can be pressed independently, it's something you have to start thinking about. In case of the Razer Raion, it uses a scheme called first input priority, meaning that if you press and hold left, then press and hold right, it will keep sending left. When you release left, then it will start sending right. If I didn't like this, I'd have to add an external SOCD cleaner between the buttons and the Raion PCB.

I posted the 3D-printable models for this stick on Printables. It uses Kailh low profile (choc v1) mechanical keyboard switches for the buttons. Here's what the final result looks like.

tag:blogger.com,1999:blog-5743520447405866726.post-1688647462314010881
Extensions
Flatbox
3d printinghidrp2040
Show full content

Having previously made some 3D printed fightsticks (arcade controllers for fighting games) that were just plastic boxes with holes for arcade buttons or mechanical keyboard switches, I started thinking, could I make one that's even thinner? On my previous designs I just soldered wires to the keyboard switches, but they're really intended to be soldered onto a printed circuit board. Using a PCB instead of the wire spaghetti inside the case seemed like a good way to shave a few millimeters off. And it turns out there are companies in China that will manufacture a custom PCB for you for very reasonable prices. And thus the Flatbox was born. I ended up making four revisions of it.

Up to this point I was using Arduino Pro Micros as the brains of my fightsticks, so it seemed natural to start with a PCB that I could solder a Pro Micro onto. The PCB would just serve as a connection between the Arduino's pins and the keyboard switches (I used Kailh choc v1 low profile switches). I designed my board in KiCAD, arranged the switch footprints in a hitbox-style layout, generated the Gerber files and sent them off to JLCPCB for manufacturing. After some days I was excited to receive a package with my boards inside.

I've never done anything like this before so I wasn't sure if the boards would even work at all. I'm used to prototyping on breadboards, if you make a wrong connection there it's usually not a big deal and it's a matter of seconds to correct it. Here if I made a mistake, not only would it cost money, but I'd also have to wait a week or two for another package from China. But fortunately everything worked great! I quickly designed and 3D printed an enclosure for it. I was very pleased with the result, just 10 millimeters thick!

I was encouraged by this initial success, but I thought having to solder an Arduino board onto my PCB wasn't very elegant. Surely an Arduino is just another PCB and I should be able to include the microcontroller and all the other necessary components on my PCB and eliminate the need for an additional board. That's what I did for revision 2. I designed the board to use SMD (surface mount) components for everything except the keyboard switches and option buttons. I would probably not be able to solder them manually, but fortunately JLCPCB will happily do the assembly for you, you just have to provide two more files in addition to the Gerbers (list of components and their placement on the board). This time I was even more afraid that it wouldn't work at all, because there was a lot more I could mess up, but surprisingly the whole thing worked on the first attempt. Because it uses the same chip as the Pro Micro (ATmega32U4), I was able to use the same firmware. I was very happy, because even though manufacturing the boards was a little more expensive, it was suddenly starting to look somewhat like a real product.

Speaking of firmware, while it's easy to make a USB HID device that works with a PC or a PS3, it is unfortunately not the case with more modern consoles. From the PS4 onwards, Sony started restricting their systems to only work with licensed controllers. Each licensed pad or stick has some special chip with a private key inside it that lets it authenticate to the console. And DIY-ers are out of luck. Except you can buy PCBs that somehow get around Sony's restrictions (I don't know how they do it). I wanted a version of the Flatbox that was compatible with the PS4 so for revision 3 I went back to the idea of soldering an add-on board onto the main PCB. I chose the Brook PS3/PS4 board because of its small size. The only SMD components on the main board are the USB port and the two resistors that it requires.

The fourth and final revision of the Flatbox again has all the components on the main PCB and doesn't require an add-on board. It is similar to revision 2, but instead of the ATmega32U4 chip it uses Raspberry Pi's RP2040. It is the revision I like best, even though it's not compatible with the PS4 or the PS5.

All the files needed to make your own Flatbox are on GitHub, including KiCAD projects for the PCBs, 3D-printable models for the case and source code for the firmware.

tag:blogger.com,1999:blog-5743520447405866726.post-6832120485759698626
Extensions
Fightsticks
3d printinghid
Show full content

Fighting games like Virtua Fighter, Tekken or Street Fighter originated at the arcades and have traditionally been played on cabinets with heavy duty joysticks and buttons. Even though they're mostly played on consoles and PCs these days, many players use arcade sticks modeled after the arcade cabinets, either because they consider them superior to controllers or simply because they enjoy their old school look and feel.

Arcade stick parts like buttons and joysticks can be bought separately so it's fairly easy to make your own stick. All that's needed is some kind of a box and a microcontroller that will read the state of the buttons and send the appropriate inputs to the PC or console. Not suprisingly, there's a thriving DIY community of fightstick makers.

I designed a few arcade stick cases meant to be 3D printed. The ones shown below all use an Arduino Pro Micro as the brains, running this firmware, compatible with PC and PlayStation 3. If you like any of them and want to try making your own, I've posted all the 3D-printable models on Printables, along with more pictures and details on how to make them.

The first one uses the most classic layout, with a Sanwa JLF joystick, 30 mm action buttons and 24 mm option buttons at the back. I made versions with 6 and 8 actions buttons.

The traditional appeal of arcade sticks doesn't mean that things are standing still. Some new stick layouts have emerged over the years, the most popular of them probably being the hitbox layout, which ditches the actual joystick and instead uses four buttons for the direction inputs. The large button at the bottom is the jump button and it's meant to be operated by either your left or right thumb. This layout seems best suited for 2D games like Street Fighter. You can see my take on this control scheme below.

Another layout that uses buttons instead of the joystick is the mixbox layout. It uses keyboard keys in a more familiar WASD shape for the direction inputs. In my opinion it's better for 3D fighters like Virtua Fighter and Tekken than the hitbox layout. Here's my version.

In addition to new stick layouts, people have also started putting alternative parts in their sticks. One move that's obvious in retrospect is to try using mechanical keyboard switches instead of the traditional arcade buttons. There are many different keyboard switches to choose from and they also allow the fightstick case to be much slimmer. Here's my attempt at a hitbox-layout controller that uses Kailh low profile keyboard switches and is just 14 mm thick (I call it the Slimbox).

Similarly, here's a mixbox-layout version of the same idea (Slimbox M).

tag:blogger.com,1999:blog-5743520447405866726.post-4004704510156778507
Extensions
Bluetooth trackball Mark II
3d printingarduinobluetoothhidmouse
Show full content

I made a Bluetooth trackball in which all the electronics are inside the ball. The ball is the entire trackball. Here it is in action:

Inside the ball there's a microcontroller and a set of sensors that together with some clever algorithms allow the microcontroller to know the ball's absolute orientation in 3D. When the ball is rotated, it sends the appropriate commands to the computer over Bluetooth to move the mouse cursor. Oh, and the keyboard in the video is a completely separate USB device, it's only used for mouse clicks and doesn't interact with the ball in any way.

This is actually the second iteration of the project. While I was very proud of my previous attempt, it had some undeniable shortcomings and was generally a proof-of-concept quality device. This new version improves upon it in many regards, to the point where I think it could possibly be used on a day to day basis as a replacement for your regular mouse. Specific features include:

  • an nRF52840 chip along with LSM6DS33 accelerometer/gyroscope and LIS3MDL magnetometer
  • a wirelessly rechargeable 500 mAh battery
  • battery level reporting over Bluetooth
  • more robust "up" calibration
  • fully sealed construction allowing for smooth rolling of the ball

I used Adafruit's Feather nRF52840 Sense, it has all the necessary sensors onboard. The other components are a lipo battery, a wireless charging coil and two reed switches, one of which is connected to the board's "En" pin, allowing us to turn the device off with an external magnet, the other is connected to a GPIO pin and is used to trigger the "up" calibration.

The ball is 65 mm in diameter and is made of two 3D printed halves. After putting the electronics inside I glued the two halves together and smoothed the surface by progressing through increasingly finer grits of sandpaper. It rolls pretty smoothly on 2.5 mm zirconium oxide bearing balls, though it's still admittedly not as smooth as a real trackball. I made a few bases in various shapes for the ball to roll on, they are just pieces of 3D printed plastic and don't have any electronics in them.

To charge the battery inside the ball I also made a special base that has a wireless charging coil inside and is powered with USB (or any 5V source). It also has a strategically placed magnet that can be used to trigger one of the two reed switches inside the ball, one will turn the device off, the other allows for setting the logical "up" directon of the trackball (by itself the trackball doesn't know which direction should move the mouse cursor up, so you can set it by putting a magnet near one of the reed switches and rotating the ball around the vertical axis).

The Arduino code and 3D models are on GitHub.

tag:blogger.com,1999:blog-5743520447405866726.post-5639131155138198905
Extensions
Dactyl Manuform build log
3d printinghid
Show full content

I made an ergonomic split keyboard using the Dactyl Manuform design, specifically the 5x6 version. I'm going to describe the process in the hope that it will be useful to someone considering making one. Here's what the final product looks like:

The Dactyl Manuform, made by Tom Short, is a modification of the original Dactyl keyboard design by Matthew Adereth. Matthew has given an entertaining talk on his design process. It won't really help with building the keyboard, but it has some nice bits on keyboard history in general.

The keyboard is controlled by an Arduino Pro Micro (one in each half) which is running the QMK firmware. This firmware is used by many keyboards, both hand-made and mass-produced and it has several useful features and allows you to customize the keyboard to a much greater extent compared to what's possible on a normal one.

Let's get to it. First we need to decide on the general shape of the keyboard and 3D print the case (or have someone 3D print it for us). I went with 5x6, meaning 5 rows and 6 columns of keys, which translates to having a row for the 0-9 keys, but not for the function keys. The fifth row only has two keys and there's also a 6-key thumb cluster. The 3D models are generated by a Clojure program that outputs a .scad file that is then converted to STL using OpenSCAD. Things like the number of rows and columns and the angles are all configurable in the Clojure code. If you don't want to mess with Clojure, there's an online generator that lets you customize some things and gives you a .scad file.

Here's what it looked like after printing in my case:

I've made some modifications to the design, fixing some issues and changing the holes for the ports to circular ones (so that they can easily be used with panel-mount sockets). I also added a hole for a reset button, which is useful when programming the thing. You can get my STL files on Thingiverse. People often cut the bottom plate from acrylic or even metal, but I just 3D printed it like the rest of the case. I also didn't use heat set inserts and just went with wood screws. Oh, and I really recommend using Cura with tree supports when printing the case. Normally I use PrusaSlicer for everything, but in this case the supports it generated were practically impossible to remove. Printing each half took about 20 hours on my Prusa MK3S.

In addition to the case, here are the parts that I used:

  • Arduino Pro Micro (2x)
  • Gateron Brown switches (64x)
  • DSA profile keycaps (60x 1u and 4x 1.5u)
  • 1N4148 diodes (64x)
  • panel-mount micro USB socket (2x)
  • panel-mount 3.5mm TRS socket (2x)
  • panel-mount momentary switch (2x)
  • some hookup wire, 24 AWG
  • 3x10mm wood screws for attaching the bottom plate (10x)

Then we need to actually wire the thing. To avoid having to use a separate wire going to the controller from every key, a matrix circuit is used, meaning the keys are arranged into rows and columns and there's a diode connected to every key. There's a wiring diagram on Tom Short's repository, but it's somewhat confusingly described as "alternative". The alternative one is the one you want.

First, we put the switches into the case. They are only press-fit mounted so be careful when removing keycaps as you can easily pull the switch out along with the keycap. Here's what it looked like before any soldering:

For the rows I used a method where no additional wire is required and the diode leads are used to connect one key to the next. Pay attention to the orientation of the diodes!

Then I wired the columns (please excuse my poor soldering skills):

Then the rows and columns need to be wired to the right pins on the Arduino:

The 3.5mm socket and the reset button also need to be wired to the Arduino and the whole thing needs to be repeated for the other side:

Then we mount the USB socket, connect it to the Arduino and try to squeeze everything inside the case. In theory the case includes a holder for the Arduino board, but I ended up not using it. With all the wires the board doesn't move around too much. I put some foam between the switches and the Arduino to avoid shorts.

Before attaching the bottom plates, test the thing! Suprisingly in my case it worked the first time with no issues.

A quick note on how the two halves work together. Each half of the keyboard has an Arduino Pro Micro board that's wired to the key matrix. In theory you could just connect each half separately to the computer via USB and it would work. But then we'd end up using two USB ports just for the keyboard and we wouldn't be able to do some clever tricks with the layout that require communication between the two halves. So instead the way it works is only one half is connected to the computer through USB and the two halves are connected to each other using a serial interface - that's what the 3.5mm jacks are for (BTW, don't connect or disconnect the 3.5mm cable while the keyboard is connected over USB):

How does the Arduino know if it's the left or the right half? By default the USB cable is supposed to be connected to the left half so that's how it decides: if USB is connected, then it knows it's the left half, otherwise it's the right half. I didn't like that very much, I wanted the freedom to connect USB to any of the halves. Fortunately that variant is fully supported, you just have to store the left/right identity in EEPROM when flashing the board. To achieve that I commented out the #define MASTER_LEFT in keyboards/handwired/dactyl_manuform/5x6/keymaps/default/config.h and uncommented #define EE_HANDS. Then to flash the left half I do:

make handwired/dactyl_manuform/5x6:default:avrdude-split-left

And to flash the right part I do:

make handwired/dactyl_manuform/5x6:default:avrdude-split-right

When the software tells you to reset the board, you double tap the reset button quickly. If you don't want to mess around with compiling the firmware yourself and generally want to avoid the command line, there's this thing called the QMK Toolbox that has a nice GUI.

And now for the fun part, defining your own layout! There's an online configurator where you can define your key mapping and download a JSON configuration file. Or you can modify the keymap.c file in keyboards/handwired/dactyl_manuform/5x6/keymaps/. If you go the JSON route, just delete the keymap.c file and put a keymap.json file in the same directory. Then flash the firmware using the commands above. Or if you're using the QMK Toolbox, the online generator can compile the thing for you.

I hope this quick report helps someone, have fun if you decide to build one yourself. I really think it's a nice project!

tag:blogger.com,1999:blog-5743520447405866726.post-360642650674787904
Extensions
Lean back to scroll
arduinobluetoothhidmouse
Show full content

You know those days when lifting a finger to scroll a website seems like to much of an effort? No, of course not, me neither. But just in case I made this so I can scroll just by leaning back in my chair:

If you look closely there's Adafruit's Feather nRF52840 Sense board attached to the back of the chair. It uses the onboard sensors to figure out the angle of the chair's back and if it's over a threshold it sends scroll down events to the computer (using the standard Bluetooth mouse protocol so it works with any OS). To set the "zero" position you press the "user switch" button on the board.

Here's the Arduino code.

tag:blogger.com,1999:blog-5743520447405866726.post-2610984810181206901
Extensions
Hat mouse
arduinobluetoothhidmouse
Show full content

I've been playing around with orientation sensors and Bluetooth HID recently. Today I'd like to show you what is perhaps my most practical application of those yet. I made a head mouse, also known as an air mouse, or in my case, a hat mouse:

The device is attached to a hat and you move your head around to move the mouse cursor on the screen. It uses the standard Bluetooth mouse protocol so it works with Windows, Mac and Linux with no additional software running on the computer. The board used is Adafruit's Feather nRF52840 Sense. The way it works is it reads accelerometer, gyroscope and magnetometer data, puts it through a sensor fusion algorithm to get orientation and then uses the yaw and pitch values to position the mouse cursor on the screen. It uses absolute cursor positioning so any given head orientation corresponds to a fixed cursor position on the screen. To reset the center position, you press the "user switch" button on the board.

Here's the Arduino code. In addition to the Feather board we need some way to power it. I used this lipo battery, but the board can also be powered over the USB port so a small power bank could work as well.

As with some of my previous custom devices that work as a mouse, unfortuntely the hat mouse has no way of performing button clicks yet. In the video above I'm using a separate USB foot switch for clicking. Depending on the movement limitations of the user, something like a sip-and-puff switch might be more appropriate (same goes for the orientation reset button that's currently located on the board). The Feather nRF52840 Sense board has a lot of sensors in addition to those that we're currently using for the orientation. Perhaps the pressure sensor or the light sensor or even the microphone could be used to make entirely head-operated switches. I have some ideas, but I decided to treat that as a separate project.

tag:blogger.com,1999:blog-5743520447405866726.post-6856401784568264250
Extensions
Plotting sensor data with MS Paint and Bluetooth HID
arduinobluetoothhid
Show full content

I have recently discovered that the HID mouse protocol supports absolute cursor positioning in addition to the more common relative mode. I think that opens interesting possibilities, one of them being we can plot real-time charts in MS Paint with no additional software running on the computer, using just the standard Bluetooth mouse protocol:

The board used above is Adafruit's Feather nRF52840 Sense, which has Bluetooth LE and lots of sensors. On the video we're plotting readings from the accelerometer. The chart is drawn by simulating mouse and keyboard inputs (keyboard is used to clear the screen when we reach the right edge).

Here's the Arduino code.
tag:blogger.com,1999:blog-5743520447405866726.post-1271310349393685242
Extensions
USB "rubber ducky" with mouse input
arduinohid
Show full content

Perhaps you're familiar with a type of device commonly referred to as a USB rubber ducky. It's a seemingly innocent device that looks like a regular USB drive, but when connected to a computer, it acts as a USB keyboard and sends malicious keystrokes to the victim's machine, as if a human typed them (but faster). The commands sent can download some unwanted software or open a reverse shell and do nasty stuff in general.

So I thought why stop at keyboard, why not also pretend to be a mouse, launch Paint and draw something funny:

The main challenge here is that a regular mouse doesn't really know where the cursor is on the screen. It only sends relative position changes like "move the cursor 7 units to the right and 2 units down". Depending on the sensitivity setting on the user's system, it might correspond to a different distance in pixels. When you add mouse acceleration into the mix, it's not really practical to try and guess where the cursor will end up being.

But, as is turns out, the mouse HID protocol also allows for absolute cursor positioning and all the major desktop operating systems support this mode (perhaps because touchscreens and graphics tablets use it?). With that knowledge, the task becomes easy, as we can just say "move the cursor to position X, Y".

I used a Digispark with a modified version of Adafruit's TrinketHidCombo library for the demo above. Here's the Arduino code.

tag:blogger.com,1999:blog-5743520447405866726.post-8911717450246328508
Extensions
Human trackball
arduinobluetoothhidmouse
Show full content

Remember Logitech's April Fools' video from 2017? The one where the gym ball works as a trackball? I made that for real:

I did this as kind of a detour while working on the next version of my Bluetooth trackball from last year (stay tuned for that). I found a board on AliExpress that has the nRF52832 Bluetooth chip from Nordic, an MPU-9250 9DOF sensor, a built-in battery charging circuit and comes with a lipo battery attached. Originally a development board for a fitness bracelet, it looked like a pretty good match for my needs.

For this application I just attached the board to the gym ball using scotch tape (and tried to avoid sitting on it or crushing it by rolling the ball).

The software is derived from my previous IMU-based Bluetooth trackball attempt. This time I decided to do the sensor fusion algorithm in software - even though the MPU-9250 is better than the MPU-6050 because it has a magnetometer (3 more DOFs!), its onboard algorithm was not updated to make use of it - it still only uses the accelerometer and gyroscope. So I used Adafruit's library implementing Sebastian Madgwick's sensor fusion algorithm. I also used Sandeep Mistry's Arduino core for the nRF52832 chip and his BLEPeripheral library for Bluetooth. I programmed the board using Nordic's nRF52 DK development kit.

You can find the code here. Also included is a sketch for calibrating the magnetometer that sends the data over Bluetooth serial (I used Adafruit's Bluefruit Connect app to read the data). And since the gym ball itself has no way of performing button clicks, I used a foot switch connected to a Digispark for clicking the mouse. A sketch for that is also included.

Even though it looks like a trackball, the ball works more like a joystick in this case: when you tilt it to the right, the cursor moves as long as the ball is kept in that position and stops moving when it is returned to the neutral starting position. Right now it's not really a practical mouse or trackball replacement, but I believe that with some fine tuning it might become a viable option. Another possibility would be to only use it for scrolling, not moving the cursor, which I haven't tested, but it should be an easy modification.

Can't wait for Logitech's next year April Fools' video!

tag:blogger.com,1999:blog-5743520447405866726.post-8920756364719276690
Extensions
Bathroom occupancy monitor
Show full content

Don't you hate it when you get up from your desk at work to go to the bathroom, only to find out that all the stalls are occupied? I did, so I made a website that shows the current status of each stall. It normally looks something like this:

To make this possible, I installed a 433 MHz door/window sensor on each stall door. Somewhere nearby I put an ESP8266 module with a 433 MHz receiver board. Each time a stall door is locked or unlocked, the module gets a signal from the sensor and passes it on to a Firebase cloud function that saves the current state and timestamp in a database. Finally there's a website that reads the database and displays the current status for everyone to see.

Even though the sensors I used are normally meant to detect when a door (or window) is opened, what I really wanted to detect in this case is whether the doors are locked. I achieved that using a zip tie and a neodymium magnet attached to the door lock:

What's nice about these sensors is that they're cheap, require no modification, and will run on a single AAA battery for many months. One thing to keep in mind is that it's important that the sensors send a signal every time they detect a state change in any direction, not just when they detect that the door/window has just been opened. Not all of the sensors on the market do that and sometimes it's not clear from the description.

The ESP8266 board I used was a Wemos D1 mini clone, here's what it looks like with the 433 MHz receiver board:

The rest is software, the ESP8266 is running an Arduino sketch and the web part uses Firebase. You can see the whole thing here. The cloud function part isn't strictly necessary, the ESP8266 could write to the Firebase database directly, but it was much easier for me to do it this way.

Right now I'm only using the website to know if the bathroom is occupied, but it might be interesting to gather some statistics, such as the average time people spend in the bathroom or how likely it is to be occupied depending on time of day.

tag:blogger.com,1999:blog-5743520447405866726.post-693031328435206345
Extensions
Darkroom enlarger timer
photography
Show full content

I have recently started making traditional prints of my analog photos and it is a lot of fun in itself, but naturally I am also treating it as an excuse to play with some electronics. I have previously described a simple timer I made for measuring how much time each print spends in the developer and fixer trays. Today I'd like to present my solution for the more important type of darkroom timer: the one that controls the exposure time on the enlarger. Here's what my setup looks like:

The enlarger lamp is connected through a reprogrammed Sonoff S20 wifi smart plug. It runs a simple HTTP server written in MicroPython. It responds to three commands: "on", "off" and "expose". The last one takes a duration in milliseconds and switches the lamp on for that time.

The second component is a smartphone app written in Flutter, so it should in theory run on both Android an iOS, but I have only tested on Android. It lets the user specify the exposure time, either directly or using a simple test strip mode. In test strip mode, exposures are made in such a way that if you cover a larger part of the paper before each exposure, the resulting exposure times of each part will be increasing in configured fractions of a stop.

Finally there's a footswitch, which is just a pedal converted into a USB keyboard using a Digispark (which is an ATtiny85 board in the shape of a USB plug that can be programmed with Arduino). Whenever the pedal is pressed, the Digispark sends an "Enter" keystroke and the smartphone app reacts as if the "START" button was tapped and starts the next exposure.

The code for all three components is available here. To run the Python code on the smart plug, first it needs to be flashed with MicroPython firmware. The smartphone app is pretty basic right now and doesn't have fancy features like dry down compensation, saving dodge/burn programs or any split-grade automation. Another useful feature would be to have the safelight connected through another smart plug and turn it off when the enlarger lamp is turned on for focusing.

Oh, and even though the app's interface is all red, it's still probably not safe for photographic paper, so it's best to cover the phone's screen when the paper is out.

tag:blogger.com,1999:blog-5743520447405866726.post-2902103395104437208
Extensions
Darkroom tray timer
photography
Show full content

Two kinds of timers are used in a darkroom when making prints. One for controlling the exposure time on the enlarger and one for measuring the time the print spends in the developer, stop bath and fixer trays. Arguably the second kind is not as critical as the first, as any clock that displays seconds can be used for that purpose. Nevertheless I've made such a timer and I'm using it regularly when making prints. Here's what it looks like:

As you can see it is operated with a foot switch and has no display. Instead it beeps when it's time to move the print to the next tray. Each press of the switch triggers the start of the next timer: first it measures 60 seconds for the developer, then 10 seconds for the stop bath, then 60 seconds for the fixer and finally 120 seconds for the wash (I'm using RC paper). After that it goes back to the first timer. A sequence of short beeps at the start confirms which timer we're currently on.

The case was designed in Fusion 360 and 3D printed in PETG. Inside there's an ATtiny85 chip, a piezo buzzer and a CR2032 battery. The code running on the ATtiny85 can be found here and a schematic of the connections is shown below. When the timer is not active it goes into deep sleep so the battery should hopefully last a long time. One thing to keep in mind when programming the ATtiny85 with Arduino is that not every core supports the tone() function, used to make sound with the buzzer. I'm using this one.

Stay tuned for the next episode in which I show my solution for the enlarger timer.

tag:blogger.com,1999:blog-5743520447405866726.post-3801723980473968573
Extensions
Bluetooth trackball with all the electronics inside the ball
arduinobluetoothhidmouse
Show full content

Update (2021-01-27): I have made an improved version of this project, see here for details.

For a while now I've been fascinated with the idea of making a trackball-type input device in which the ball itself would be the entire device. Unlike a regular trackball, where the ball is just a ball and registering its motion and communicating with the computer is done by external sensors and chips, here everything would live inside the ball. And now I have finally done it. Here's a video:

And here's how I did it. For obvious reasons, the device couldn't use USB, it had to be Bluetooth. For registering the rotation of the ball, a combination of an accelerometer and a gyroscope seemed like a good way of ensuring smooth results. I ended up using the following components:

I designed the ball itself in Fusion 360 and then 3D printed it. It has a diameter of 10 centimeters and consists of three parts, two halves of the ball and an inside part that holds the electronics and the battery. The three parts screw together to form the ball. I also made a stand on which the ball can be rolled, but that's just to make it easier to use as a trackball, the stand is optional and the device works when held in the air as well.

Here's what it looks like inside (the MPU-6050 is under the battery):

For the software part, I was pleasantly surprised when I found out that the MPU-6050 chip can do the sensor fusion magic (combining the outputs of the accelerometer and the gyro) for us and just give us the 3D orientation in the form of a quaternion. What's left then for the Arduino to do is to read the current orientation, calculate the difference between the previous orientation and the current one, translate it to X and Y mouse cursor offsets and send the appropriate commands to the Bluetooth chip that will pass them on to the computer.

Here's the Arduino code.

You may wonder how the ball knows which direction the cursor should go when it's rotated in a certain direction. The answer is of course that it doesn't, so the initial mapping of the directions might not be correct. But it does know which way is up (because it has an accelerometer), so the directions can be calibrated by rotating the ball around the vertical axis.

While I personally consider this project a great success, there's always room for improvement. For example, the trackball would be a little more practical if it had the ability to click, not just to move the cursor. I explored the idea of detecting taps on the ball using the accelerometer, but found it hard to eliminate false positives. This area needs some additional work.

An obvious shortcoming of the current solution is that to switch the device on or off, I have to unscrew the two halves and connect or disconnect the battery. Ideally there would be some way of doing that without disassembling the ball, a magnetic switch of some sort or maybe the device could always be on and just go to sleep when it's not used for a while (like regular wireless mice do).

On a related note it would be really cool if we also didn't have to open the ball to change the battery. Seems like a good use case for wireless charging.

If I ever do a next version of this, I will probably try to use a different Bluetooth board, one that's not discontinued (and perhaps can do Bluetooth LE).

tag:blogger.com,1999:blog-5743520447405866726.post-5112845906581627527
Extensions
Time tracking wifi cube
Show full content
There are many apps and websites for tracking time spent on projects and I'm sure they work well. But I like physical objects so I made a gadget - a cube that you can flip to a different face to indicate that you're now working on some project or task. Each face corresponds to a different project and one of the faces means you don't want to track time anymore. The idea is of course not original, there are similar commercial products available, but hey, this one's mine.


I had two design goals: first, I wanted the gadget to be standalone and not need a companion app on a phone or a computer. So it needs to have wifi and talk directly to the Internet. Second, I wanted the cube to last a long time on battery, at least a few months. So I had to learn a bit about how deep sleep modes work on microcontrollers.

Here's a video that shows the cube in action. (The laptop is just there to show that time reporting works, as I said the cube talks to the Internet directly.)



These are the parts that I used to make this happen:

  • ESP8266 board (Wemos D1 mini) for wifi
  • MPU-6050 accelerometer to check which side the cube is flipped to
  • SW-18010P vibration sensor for detecting motion
  • ATtiny85 chip for watching the vibration sensor and waking up the wifi chip
  • MCP1826 voltage regulator with a shutdown pin that made it easy to switch the wifi chip on and off

The idea here is that most of the time the ESP8266 chip is off and the ATtiny85 chip is in deep sleep, using almost no power from the battery. It is set to wake up when the state of one of its pins changes - a pin connected to the vibration sensor. Then the ATtiny85 chip enables the voltage regulator, waking up the ESP8266 chip, which reads the orientation of the cube from the accelerometer and makes a HTTP request to report it to a time tracking service. When it's done it signals the ATtiny85 chip on another pin. The ATtiny85 then disables the voltage regulator and goes back to sleep, waiting for another interrupt on the vibration sensor pin. An LED indicates when the chips are awake.

Here's a schematic of the connections. You may notice an extra button, I will explain its purpose in a moment.


And here's the code: the part running on the ATtiny85 is done in Arduino and the ESP8266 part in MicroPython.

I used Toggl for tracking time, but any service with a reasonable API could be used, the cube just makes HTTP requests.

Since the cube is woken up by motion, we have to consider what happens when you put it in a bag and take it with you. We don't want it to wake up constantly and deplete the battery. So here's how it works. The ESP8266 chip reads the accelerometer and waits for the readings to settle before making the HTTP request and signaling the ATtiny85 to go to sleep. So if the cube keeps moving, that signal never comes. And the ATtiny85 chip has a 30 second timeout. If it doesn't receive the signal before the timer runs out, it switches to "travel mode". Which means it goes back to sleep, but now it ignores the vibration sensor - it will only be woken up when the button is pressed. When it's pressed, it goes back to normal mode. That way we still get the long battery life, but we can take the cube with us.

Currently pressing the button is not very convenient as the cube needs to be opened up to access it.

Another improvement that comes to mind is making it work with multiple wifi networks. Currently it only remembers one, which makes it hard to use the same cube at, say, home and work.

tag:blogger.com,1999:blog-5743520447405866726.post-6453839786949397250
Extensions
Google Assistant support for IKEA TRÅDFRI lights
googleikea
Show full content
Update (2018-04-21): IKEA has rolled out official support for Google Assistant, so if you just want your lights to work with Google Home, you don't need any of this. If you're interested in the technical side, you may still find this post useful.

Earlier this year I got some IKEA smart lights from their TRÅDFRI line. They can be controlled by a remote and also through a smartphone app, if you have IKEA's gateway. Around the same time I also got a Google Home and naturally I wanted them all to work together. IKEA is planning to add official support for Google Assistant very soon, but in the meantime I rolled out my own. So while all this may be obsolete soon, I still wanted to publish it in the hope that it might be useful for someone (perhaps for adding Assistant support to some other smart lighting system without official support). Below I try to provide a step-by-step description of how I got it to work, but if you just want to see the code, here it is.

Let's get started. We're going to need a computer on the same network as the IKEA gateway (or it must be able to reach it though some clever routing). I used a Raspberry Pi, but any computer running Linux will do. This computer needs to have its 443 port accessible from the Internet, so if it's behind a router, you need to configure port forwarding. We're also going to need a domain name that will point to our Linux box and a proper SSL/TLS certificate for that domain. I'm not going to go into details about these, but you can easily get a certificate for free at Let's Encrypt. Below I'm using home.example.com as the domain name, obviously you should change it to your actual domain wherever it appears.

The general architecture of the solution is as follows. We're going to create a Smart Home App on Actions on Google and deploy it in testing mode. Then when we talk to the Google Assistant (on Google Home or a phone or a smartwatch), Google's cloud magic will make a call to our server, asking what lights are available or telling it to turn a certain light on or off. Then our app will talk to the IKEA gateway, which in turn talks to the light bulbs themselves. Using the Actions SDK instead of IFTTT means we will get to use more natural language commands without defining each phrase manually.

Google's documentation likes to give all the examples in node.js, but the app can by anything as long as it speaks the proper API over HTTP. I wrote mine in Python using Django and deployed it using nginx and uwsgi, but any other way of deploying a Django app would also work.

Let's get the code (below I assume we're running as the pi user, change to your actual user and group if they're different):
sudo mkdir /var/www/home.example.com
sudo chown pi:pi /var/www/home.example.com
cd /var/www/home.example.com/
git clone https://github.com/jfedor2/ikea-tradfri-google-assistant.git .
One more thing we're going to need is the coap-client tool, compiled with DTLS (encryption) support. It's what we're going to use to talk to the IKEA gateway. I'm going to borrow the instructions for compiling it from here:
sudo apt-get install build-essential autoconf automake libtool
git clone --recursive https://github.com/obgm/libcoap.git
cd libcoap
git checkout dtls
git submodule update --init --recursive
./autogen.sh
./configure --disable-documentation --disable-shared
make
sudo make install
Once we have the coap-client tool installed, there's a one-time step that we need to perform to set up an identity that we'll use to authenticate to the IKEA gateway (in other words, a login and password). For that we will need to know the gateway's IP address on the local network and the security code that's printed on the bottom of the gateway. Also we need to come up with an identity (username) that we'll use. This can be anything, e.g. "foobar". With those in hand we run the following command (substituting the appropriate values):
coap-client -m post -u Client_identity -k 'security code' -e '{"9090":"chosen username"}' "coaps://IP address of your IKEA gateway:5684/15011/9063"
The gateway should reply with a pre-shared key that we'll use for authentication. Write that down somewhere.

Let's get back to our app and actually make it work. First, let's create a Python virtual environment for the app so that we can install the necessary modules locally:
cd /var/www/home.example.com/
virtualenv .virtualenv
. .virtualenv/bin/activate
pip install -r requirements.txt
Then we need to edit the Django settings file. You can either edit /var/www/home.example.com/tradfri/settings.py or leave that file unchanged and create a new file, /var/www/home.example.com/tradfri/local_settings.py, with just the settings that need changing locally. (That way it's easier to keep settings.py under version control.) You need to provide the following settings:
SECRET_KEY = 'insert a long string of random characters here that you will keep private'
ALLOWED_HOSTS = ['home.example.com']
COAP_CLIENT = '/usr/local/bin/coap-client' # or wherever you installed it
IKEA_IDENTITY = 'the username we chose above'
IKEA_PRE_SHARED_KEY = 'the pre-shared key that the gateway provided'
GATEWAY_ADDRESS = 'IP address of your IKEA gateway'
Depending on your local network configuration, it may also be useful to add the local IP address of your Linux computer to ALLOWED_HOSTS (if you're using port forwarding on the router, accessing the server through the proper domain name might not work from inside the network):
ALLOWED_HOSTS = ['home.example.com', '192.168.0.x']
Then, create the necessary tables in the database (run the following commands in the Python virtual environment created above - run the activate command before if you haven't already in this shell):
./manage.py migrate
And let's create a user that we will use for OAuth2 account linking:
./manage.py createsuperuser
Choose whatever username and password you want and remember them.

In the extras directory, I provided example configuration files for nginx and uwsgi, home.example.com.conf and home.example.com.ini. Edit them with your specific settings and put them in /etc/nginx/sites-enabled/ and /etc/uwsgi/apps-enabled/, respectively.

After updating the configuration files, restart uwsgi and nginx (install them first if necessary):
sudo apt-get install nginx uwsgi-plugin-python
sudo service uwsgi restart
sudo service nginx restart
Whenever you change something in the Django app, you need to restart uwsgi.

In the extras directory there's also an actions.json file, that we will use to tell Google where to look for our app. But first we need to create a project for it.

Go to the Actions on Google console. Click "Add/import project", choose a name and click "create project". In the "Add actions to your app" section, click on "Actions SDK". It will give you an example command that looks something like this:
gactions update --action_package PACKAGE_NAME --project smartlights-abc12
smartlights-abc12 is your project ID, which you will need in a moment.

Update the /var/www/home.example.com/extras/action.json file with your actual domain name, download the gactions command-line tool and run it, substituting the actual project ID of course (you may have to provide a path to the tool if it's not in your PATH):
gactions test --action_package /var/www/home.example.com/extras/action.json --project smartlights-abc12
This will put your app in testing mode and make it accessible in the Google Home app on your phone (you have to be using the same Google account). Google says an app only works in testing mode for 3 days, but I found that in reality it works indefinitely.

In the Google Actions console you probably also need to provide some text and graphics for your app. It doesn't matter what you put there (no-one else is going to see it).

Now all that is left is to set up OAuth2 for account linking. We need to configure it on both our app and the Actions on Google console. Go to https://home.example.com/oauth2/applications/ or http://192.168.0.x/oauth2/applications/ (substituting the correct address of course). Log in using the user and password you created with createsuperuser. Click "New Application". Put some name in (I used "google"), note the client ID and client secret (you're going to need them in a moment), choose "client type": "confidential", "authorization grant type": "authorization code" and put https://oauth-redirect.googleusercontent.com/r/smartlights-abc12 in "redirect uris" (substituting your project ID from above). Click "Save". Now go to the Actions on Google console and in your project go to "Account linking". Choose "Authorization code" under "Grant type" as before. Under "Client information", paste the client ID and client secret that you saw in our app's web interface a moment ago. Then put https://home.example.com/oauth2/authorize/ under "Authorization URL" and https://home.example.com/oauth2/token/ under "Token URL". Click "save".

We're almost done. Open the Google Home app on your phone. Open the hamburger menu and tap "Home control". Tap the plus icon in the bottom right corner. This should give you a long list of devices that are officially supported by the Google Assistant, but also our humble app should be there on the very top, with its name prefixed with "[test]". Tapping it should take you to a login form on our app. Login with the user and password you created with createsuperuser a few minutes ago and on the next screen confirm that you want to give Google access. (You may have to disable wifi on your phone and use the cellular network connection for this step if https://home.example.com/ doesn't work from inside your local network.)

Boom, that's it. You should get a list of your IKEA lights and be able to control them with Google Assistant.

Update (2017-12-04): With version 1.2.42 of the IKEA gateway firmware, the authentication scheme changed. The code and this post have been updated accordingly.

tag:blogger.com,1999:blog-5743520447405866726.post-4394948651063026802
Extensions
External notification light for your phone
androidarduinobluetooth
Show full content
Among other interesting things, Android 4.3 introduced a proper way of accessing notifications from an app. I used this API to make an external notification light for my phone:



It uses Adafruit's Trinket, a Bluetooth serial board from dx.com to talk to the phone and it's powered via USB. Here's a diagram of the connections:



The Arduino sketch that's running on the Trinket is very simple, it listens on the serial line that's connected to the Bluetooth board and turns the LED on and off depending on what character is received. You can see the sketch here. On Android side, the code is also pretty simple, there's an intent filter in the manifest to register a listener that gets called whenever a notification is posted or dismissed. In the listener we check what notifications are active and if they requested the notification light to be turned on (your phone might not even have a notification light, but the information is still there). Then we connect to the Trinket via Bluetooth and tell it to turn the LED on or off. You can see the code here. There is no UI and the Bluetooth address is hardwired.

There is no special permission in the manifest to let the app access notifications, instead you grant access via a checkbox in the security section of your phone's settings:



As usual, there's room for improvement. For example if the phone fails to connect to the device via Bluetooth (because it's out of range or powered off), it should probably try again in some time. Also, we could have an RGB LED and send color and timing information, instead of just on/off state, to better replicate the behavior of the notification light.
tag:blogger.com,1999:blog-5743520447405866726.post-1050569631862462273
Extensions
Morse code Bluetooth keyboard
arduinobluetoothmorse
Show full content
My previous attempt at a Morse code keyboard worked over USB and used a copper coin as a capacitive sensor. Since then I've acquired a real telegraph key and Adafruit's Bluefruit EZ-Key board. With that and a Trinket I made a Morse code Bluetooth keyboard. It works with any computer that has Bluetooth (also phones and tablets).



Here's what it looks like in action (as usual please excuse my lack of Morse code skills):



Here's the Arduino sketch that's running on the Trinket. As before there's a buzzer for feedback and the transmission speed is fixed.

If you're into Morse code, I continue to recommend my Android application that listens to Morse code using your smartphone's microphone and translates it to text.

Here's a diagram of the connections:

tag:blogger.com,1999:blog-5743520447405866726.post-1666428111774005423
Extensions
Bluetooth mouse from a Wii nunchuck
arduinobluetoothhidmouse
Show full content
I never had a Nintendo Wii, but I got a nunchuck controller to play with. It has a joystick, two buttons, an accelerometer for orientation sensing and the third-party ones are dirt cheap. It turns out that it's really easy to talk to them from an Arduino too, because they speak I2C and as you would expect the protocol is well documented on the Internet. I used Adafruit's Trinket, Bluefruit EZ-Key and a 100 mAh lipo battery to turn the nunchuck into a Bluetooth mouse:



Here's a diagram of the connections, pin 1 on the Trinket goes to the RX pin on the Bluefruit and pins 0 and 2 are used for the I2C communication with the nunchuck:



On the software side, I used the WiiChuck class I found here, but I modified it to use the TinyWireM library for I2C. It is equivalent to the standard Arduino Wire library, but it runs on ATtiny chips like the one used by the Trinket. I also used this SendOnlySoftwareSerial library. Here's my sketch and the modified WiiChuck library.

I haven't found any clever use for the accelerometer inside the nunchuck yet, perhaps it could somehow be used for scrolling.

tag:blogger.com,1999:blog-5743520447405866726.post-5844331943806743486
Extensions
Bluetooth emergency mute button
arduinobluetooth
Show full content
Some time ago I made an emergency mute button that connected over USB. Now with Adafruit's Bluefruit EZ-Key I made a wireless version that works over Bluetooth. Look, no wires:



In addition to the Bluefruit board, I used a Trinket and a 100 mAh lipo battery. It all fit nicely inside the button:



Here's a diagram of the connections:



There's no on/off switch and to charge the battery I have to disassemble the whole thing, but hey, nobody's perfect. Here's the Arduino sketch that's running on the Trinket, it simply sends the "mute" key code when it detects a change in the state of the button. I'm using this SendOnlySoftwareSerial library, because I'm only sending data to the Bluefruit board.

(You will notice that it still suffers from the synchronization problem that the USB version had - if you mute audio on your computer some other way than using the button, then pressing the button will actually unmute audio. It's because the button is stateful, but has no way of finding out what the actual state of audio on the computer is and there are no separate key codes for muting and unmuting.)
tag:blogger.com,1999:blog-5743520447405866726.post-1297997674275864800
Extensions