Later addition: you can find sources here.
I've been thinking about rudimentary home automation stuff, specifically remotely controlled heating to our cabin. Since it has munincipal water it must remain above freezing temperature, but I'd rather not keep temperature too high (i.e. near comfortable) when we're not there to save electricity, so it's often around +10 degrees C when we go there, and it takes almost a full day for it to warm to more comfortable +20 C. Not great situation.
I already have temperature monitoring in place, with remote reporting (to send an alarm if it gets too cold and needs attention, and also for curiosity monitoring the temperature from home), but controlling heaters - that is, mains voltages - is something I'd rather not fiddle with directly. Although I have no double could make it safe, there's still the issue of pesky insurance claim denials in case something were to happen.
For this purpose I bought a set of remote controlled sockets with sufficient power rating. These are controlled with 433MHz radio signal, so I would have to duplicate signals sent by remote somehow.
I did some web searching and there is actually some articles about this, but they all work on higher level than I'd like. "take Arduino and use this library" is not my thing, really. But those anyway gave me enough pointers to start moving to right direction.
I bought some cheap receivers from certain large internet dealer, but somehow managed forgot to buy transmitters! Damn it. But at least I could start with signal decode part.
This turned out to be slightly more difficult than I though, as either my surroundings is full of 433MHz signals, or these receivers are horribly noisy even when there is no signal around, as presented by this scope capture of actual signal amongst noise. Yellow is output signal of receiver, and small green dots indicate locations where there is end of actual transmitted signal as parsed by (my eventual) system.
Here the original transmitter probing came in handy. I knew that sequence started with short high, followed by fixed length low, followed by actual PWM signal. Getting scope trigger to that reliably wasn't happening, but managed to get it trigger on specific-length "low" often enough to verify that my initial assumptions are correct.
Here's a bit closed look at actual transmitted signal. Start of signal is marked with cursor X1, and end (as I think it is) by X2. At start there's short, 2000us zero pulse, followed by 24-bit PWM coded signal, then possibly "stop bit" of some kind. PWM signals are 380us for "0" and 1200us for "1" (or other way around, I don't really care - I just want to be able to replicate it.) Next pulse starts always 1500us after previous one, regardless of width of pulse.
I already had thought of the receiver software that could parse this (and other similar signals) with MCU I had ready to go - STM32 series chip (and system) I've used often recently. The idea is this:
Connect receiver output to STM32 I/O pin that can handle external interrupts. I set this line to handle both rising and falling edge interrupts, to stop on both edges.
I already use the RTC part of STM32 with 32768 Hz clock crystal on it. It has sub-second counter (SSR) which I set to to count to 8192 on every second - 122us per tick. Not great resolution but sufficient here (there is also small power cost involved with higher rates when using battery backup, although it is not important here as I do not need to optimize for that), as "0" and "1" signals have significant time difference. Any hardware timer that allows its internal counter to be read reliably should be fine for this though.
As there is a lot of noise, and thus lots of interrupts here, I designed the interrupt handler to be as short as possible for common case - no recognizable signal, or start of false signal - to reduce time spent there.
When idle, system looks for low period of 1800us or more to start decoding signal. (trigger SSR read on lowering edge, then check elapsed time on rising edge, calculate elapsed time in ticks - obsiously taking care of wraparounds in calculation if there are some).
After this, on lowering edge SSR is read and time compated; I accept fairly wide range of values; around 200us to 500us as "0" and 900us to 1500us as "1". If timing is out of these bounds, signal is treated as noise and system returns to idle (this large scale is in case I want to use modules with slight timing differences, such as radio-based temperature sensor I haven't tested yet. Also there is the issue of SSR having 122us resolution, so I could expect half of that as average timing error, and also other interrupts that might have blocked this handler temporarily)
Next rising edge is also checked; it must have happened from 1300us to 1700us after before. Again, falling outside this range is noise and system returns to idle, waiting next signal. If timing was correct, system waits for lowering edge, i.e. next bit. After 24 bits data treated as successfully received.
This turned out to be more reliable than I expected, as system received all four identical sequences sent by remote extremely reliably, without any false positives so far. For further proof system might check with majority vote the actual received value, but that has to wait for now.
Next, playing with receivers some more.