Code and Life

Programming, electronics and other cool tech stuff

Supported by

Supported by Picotech

Using a Soundcard as an Oscilloscope to Decode 433 MHz Smart Power Plug Remote Control Signals

I previously covered how to decode Nexa smart power plug remote control signals using Arduino Uno. The drawback of Arduino was the limited capture time and somewhat inaccurate timing information (when using a delay function instead of an actual hardware interrupt timer).

Another way to look at signals is an oscilloscope, and a soundcard can work as a "poor man's oscilloscope" in a pinch. You wire the signal to left/right channel (you could even wire two signals at the same time) and "measure" by recording the audio. It helps if ground level is shared between the soundcard and the signal source. In this case I achieved it pretty well by plugging the Arduino that still provides 3.3V voltage for the 433 MHz receiver chip to the same USB hub as the soundcard.

Another thing to consider is the signal level. Soundcard expects the voltage to be around 0.5V, whereas our receiver is happily pushing full 3.3V of VCC when the signal is high. This can be fixed with a voltage divider -- I wired the signal via a 4.7 kOhm resistor to the audio plug tip, and a 1 kOhm resistor continues to GND -- effectively dropping the voltage to less than a fifth of original.

The audio plug "sleeve" should be connected to GND as L/R channel voltages are relative to that. There was a 0.1V difference in voltage between soundcard sleeve and Arduino GND so I decided to put a 1 kOhm resistor also here to avoid too much current flowing through a "ground loop".

Note that I'm using a SparkFun breakout for the plug that makes connecting the plug to a breadboard quite easy. If you need to wire it directly to the connector (signal to "tip" and ground to "sleeve"), refer to diagram here: https://en.wikipedia.org/wiki/Phone_connector_(audio). A word of caution: You can break stuff if you wire it incorrectly or provide too high voltage to some parts, so be careful and proceed at your own risk!

Soundcard as an Oscilloscope

You can see the circuit in the picture above. Note that due to receiver needing GND in two places, I've been able to connect the sleeve to another GND point (rightmost resistor) than the other 1 kOhm resistor that is part of the voltage divider (leftmost resistor)

Trying it out with Audacity

Once you have power to the receiver, and 1 kOhm resistors to sleeve and tip and signal through a 4.7 kOhm (anything between that and 22 kOhm works pretty well with 16 bits for our ON/OFF purposes), you can start a recording software like Audacity to capture some signals. Here is a sample recording where I've pressed the remote a couple of times:

Audacity example

As you can see, our signal is one-sided (audio signals should be oscillating around GND, where as our is between GND and +0.5V) which causes the signal to waver around a bit. If you want a nicer signal you can build a somewhat more elaborate circuit but this should do for our purposes.

By the way, you can use ctrl-A to select all of the recorded audio and use the "Amplify" effect (with default settings) maximize signal to available audio headroom. Makes looking at the signals a little easier. I've done that before the captures below. Another issue becomes apparent when we zoom in a bit closer:

Audacity example two: zoomed in

Due to automatic gain in the receiver chip (or maybe some other anomaly), the receiver consistently captures some "garbage signal" some 200 ms after the "official" Nexa signal we got a glimpse of in the [previous part of this series]. It is not pure noise but seems to contain some other signal, probably coming somewhere else in the building but at a much lower power level -- the receiver records this as well, but blocks it for a while once it gets the more powerful Nexa signal.

To analyze the Nexa signal, I suggest deleting other parts of audio capture than the actual signals. I actually tore open the Nexa remote and measured the signal straight from the antenna to make sure this recurring "tail" is not coming from the remote. :D

Below you can see a zoom-in of the signal at various levels of magnification. Note that I'm not zooming in on the first signal that has the "spike" before the actual signal starts.

Nexa remote signal zoomed in Nexa remote signal zoomed in more Nexa remote signal zoomed in even more

As you can see, the 44.1 kHz signal has enough resolution to deduce the signal protocol just with Audacity. But countint the individual samples from HIGH and LOW segments to get an average length is pretty tedious. If only we could do it programmatically...

Using Python to analyze the recorded signal

I made a handy Python script to analyze the recorded signal. Basic procedure is:

Read post

Analyzing 433 MHz Nexa Smart Power Plug Remote Control Signal with Arduino Uno

A friend recently started a project to remotely boot his router (which tends to hang randomly) with Raspberry Pi. Unfortunately, the rpi-rf tool was not quite recognizing the signals. I pitched in to help, and as he did not have access to an oscilloscope, but had an Arduino Uno, I thought maybe I could figure it out with that.

Fast forward a few weeks later, I have been experimenting with four methods analyzing my own Nexa 433 MHz remote controller:

  1. Arduino Uno
  2. Soundcard a.k.a. "poor man's oscilloscope"
  3. Raspberry Pi
  4. An actual oscilloscope, namely my Picoscope 2208B

Having learned a lot, I thought to document the process for others to learn from, or maybe even hijack to analyze their smart remotes. In this first part, I will cover the process with Arduino Uno, and the following posts will go through the other three methods.

Starting Simple: Arduino and 433 MHz receiver

Having purchased a rather basic Hope Microelectronics (RFM210LCF-433D) 3.3V receiver for the 433 MHz spectrum signals, it was easy to wire to Arduino:

  1. Connect GND and 3.3V outputs from Arduino to GND and VCC
  2. Connect Arduino PIN 8 to DATA on the receiver
  3. Connect a fourth "enable" pin to GND as well to turn the receiver on

You can see the setup here (larger version):

Arduino wired to Hope 433 MHz rf receiver

I wrote a simple Arduino script that measures the PIN 8 voltage every 50 microseconds (20 kHz), recording the length of HIGH/LOW pulses in a unsigned short array. Due to memory limitation of 2 kB, there is only space for about 850 edges, and the maximum length of a single edge is about 65 000 samples, i.e. bit more than three seconds.

Once the buffer is filled with edge data or maximum "silence" is reached, the code prints out the data over serial, resets the buffer and starts again, blinking a LED for 5 seconds so you know when you should start pressing those remote control buttons. Or perhaps "press a button", as at least my Nexa pretty much fills the buffer with a single key press, as it sends the same data of about 130 edges a minimum of 5 times, taking almost 700 edges!

It also turned out that the "silence" limit is rarely reached, as the Hope receiver is pretty good at catching stray signals from other places when there is nothing transmitting nearby (it likely has automatic sensitivity to "turn up the volume" if it doesn't hear anything).

#define inputPin 8 // Which pin to monitor

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(38400);
}

#define BUFSIZE 850
#define WAIT_US 50 // 20 kHz minus processing overhead

unsigned short buf[BUFSIZE];
short pos = 0;
bool measure = false;

void loop() {
  if(measure) {
    unsigned char data = digitalRead(inputPin) == HIGH ? 1 : 0;
    if(data == (pos&1))
      pos++; // data HIGH and odd pos or LOW and even -> advance
    
    if(buf[pos] > 65000 || pos >= BUFSIZE) {
      measure = false;
      return; // avoid overflow
    }
    
    buf[pos]++;
    delayMicroseconds(WAIT_US); // Wait until next signal
  } else { // end measure
    digitalWrite(LED_BUILTIN, LOW); // LED OFF = dumping
    Serial.println();
    Serial.print("N =");
    Serial.println(pos, DEC);
    for(int i=0; i<pos && i<BUFSIZE; i++) {
      Serial.print(buf[i], DEC);
      if(buf[i] > 100000/WAIT_US)
        Serial.println(); // 100 ms delays get a newline
      else
        Serial.print(' ');
      buf[i] = 0; // reset
    }
    pos = 0; // restart
    measure = true;
    for(int i=0; i<10; i++) { // 5s blink before next measurement 
      digitalWrite(LED_BUILTIN, (i&1) ? LOW : HIGH); 
      delay(500); 
    }
    Serial.println("\nGO");
    digitalWrite(LED_BUILTIN, HIGH); // LED ON = measuring
  }
}

Analyzing the data

Here is some sample data from the serial monitor:

Read post

Ugreen M.2 NVME drive enclosure with USB-C 3.1 test

I’ve been occasionally doing backups of critical files to an external hard drive (in addition to cloud of course :). However, my nice portable drive was only 500 GB and lately I’ve pushed over 600 GB with my Nikon D7200 RAW files. Time for a new drive! Instead of boring mechanical, I noticed that the very nice NVME SSD with Adata XPG SX8200 Pro with 1 TB capacity was available nearby for just 140€ (ca. $150)!

Commercial alternatives like Samsung T5 cost around 230€ here, so I thought I’d get one of those M.2 enclosures. Unfortunately, the ones with NVME support started from 50€ up in Finnish web stores.

Ugreen to the rescue

When you have something like M.2 enclosure, you know every manufacturer actually puts Chinese electronics inside. Thus, AliExpress seemed like an obvious destination to check out. I’m bit doubtful to order actual NVME drive (there were some cheap flash drives in the past that did not actually have the reported capacity), the enclosure should be fine.

Enter Ugreen, my favorite in AliExpress store. I’ve purchased several chargers from them, many having QuickCharge functionality, and the packaging, quality and everything are always top notch. Therefore I was more than happy to find a range of NVME enclosures from them for just $15-30:

Ugreen M.2 SSD USB enclosures (from Ugreen product page)

Time to order one! Fast forward 2½ weeks of anxious wait…

Unpacking and installing SSD to M.2 enclosure

I got the NVME model which promised up to 10 Gbit/s data rates, and chose the option with extra USB cable as I don’t have USB-C ports on my MB. The package arrived a bit faster than the promised 21-25 days. See the gallery below for glorious images of various stages of setup.

Read post

TrinketMIDI updated with volume control demo

Just a quick update this time: A long while ago I made a post about using Adafruit Trinket without Arduino and later converted that into a TrinketMIDI Github repository for making a MIDI device with ATtiny:

https://github.com/jokkebk/TrinketMIDI

Now thanks to a contribution by Gerhard Zintel, there is now also a MIDI volume device sample code in the repo. If you want to make a MIDI volume controller, it should be pretty easy with the code as well. Enjoy!

Read post

Filco Majestouch-2 TK (MX Blue) with Dolch keycaps

Note: The keyboard and keycaps in this article are bought by me and not a review sample. I have, however worked with KeyboardCo in the past and like them a lot in general. But just so you know!

A new keyboard in the house! Namely the Filco Majestouch-2 TK (MX Blue) Always an exciting happening in the family. After typing happily for a couple of years with superbly compact and slim Apple Magic Keyboard (works fine with Windows btw.) at home, and with my Topre Realforce 88UB at work, I thought it would be fun to get a keyboard with the classic clickly MX blues.

My main reason to get Cherries apart from the amazing blue clicky sound is the fact that one can get a wide selection of custom keycaps, very much unlike the Topre ones where you’re pretty much stuck with the keys they came with, or maybe some with Japanese characters.

After some consultation in Geekhack, I decided that out of the options I had available (in Finland pretty much zero apart from some gaming keyboards), Filco would be a good choice. Knowing they stock it, I headed straight to The Keyboard Company  website and after some deliberation opted for one in Scandinavian layout — easier to swap here in Finland if I want to switch again. The Filcos are in no way inexpensive, but knowing the amount of time I spend typing, I considered the hourly cost to be quite reasonable.

Unboxing Filco Majestouch

The delivery from KeyboardCo arrived promptly as always, and I decided to shoot a classic unboxing video. Notice the great “Code and Life” logo in the thumbnail! There are no audio comments in the video, but you can hear the clickies quite well.

As an “out of the box” experience, here are my major plusses and minuses list:

Plusses
  • Very solid build, the case will definitely last a lifetime
  • Great MX blue typing experience and satisfying sound
  • Compact layout, it doesn’t expand much outside the keys in any direction
  • It’s a “no frills” workhorse, not much more to be said!
Minuses
  • Standard keycaps are quite high, making a wrist support pretty much a must
  • There’s nothing particularly exciting or special about they look

Read post

Correcting image white balance with Python PIL and Numpy

I started writing another blog post about my new keyboard today, and when uploading the unboxing video to my YouTube channel, I realized they have no “auto white balance” option, not in their new or old video editor either. Shoot. After googling for free video editors, I settled on OpenShot.

And guess what? OpenShot doesn’t have a white balance setting either! The author himself said this on Reddit, asking for help to implement it. I was pretty shocked, as it seems like the first filter I would implement myself, and thought “surely it doesn’t take more than five minutes to implement one, right?”. So I did. Well, it took maybe 15 minutes, plus 45 fiddling with Jupyter notebooks to get PIL and numpy commands right.

The Python 3 code above basically loads an image (either local if you run it with Jupyter notebook locally, or over network), get a small subportion of it to act as a grey reference, and adjusts color channel balance with two alternate methods: RGB or YCbCr. More advanced versions should be easy to add as well.

You can view the above gist in Github or just copy-paste the code to your own / cloud based notebook to try it out:

https://gist.github.com/jokkebk/7a0feab274356768b515db6b05f124bf

If you don’t have access to anything that can run a ipynb file, you can just take a look at the PDF version of a sample run. Enjoy!

Read post