Keeping a running average of the kind you proposed in the first post is a good start. You have essentially two signal levels: ambient (which varies over time), and ambient plus signal. You just need to get that "plus signal" part. You will need to be smarter than "if signal>ambient"; you will need some threshold... how much greater than? otherwise noise will ruin you.
Also consider that when sending a data stream, you need some concept of framing. If you just send "00000001", and "0" means LED off, then how do you know where the first "0" bit is? UART takes care of this by always sending a start bit followed by (usually) 8 data bits, followed by a stop bit. In UART (TTL level, not RS232 level), the idle condition is high, a start bit is low, data is 0=low, 1=high, and the stop bit is a high. Each byte is then 10 bits (baud) long, and there can be any amount of time between bytes since the start of each byte is demarked by a framing bit at the start.
Another way to avoid the framing problem is to ensure that both 0 and 1 bits use both on and off states of the link. So a "0" bit might be 1 usec LED on followed by 3 usec off, and a "1" bit is 3 usec LED on followed by 1 usec off. Then, all on the Rx side, you need to detect the edge (when off -> on), wait exactly 2 usec, then sample the signal... it will be off for a 0 bit and on for a 1 bit. Then you wait for "off", and wait for the next off->on transition for the start of the next bit. repeat. Using this, the start of each bit is individually demarked by a off->on transistion, so you have some leeway in timing. For UART, you must by no more than 2% off of nominal or the signal may become errored (total error must be less than 5%, since this accumulates to 50% error in the timing of the 10th bit, meaning that the 10th bit may be sampled at the wrong instant... so each Rx and Tx must be <2.5% error).
Sometimes we want to send a serial stream over noisy links like simple ASK RF (those cheap $1 433 MHz modules on ebay etc.). These modules use a automatic gain on the Rx, so when the link is idle, the signal is boosted until the noise creates signal transitions. So the Rx side UART is always getting noise. For this reason, the microcontroller must be smart. First, the UART will probably throw lots of framing errors, but even when it does receive a byte of data, it is discarded unless it matches some kind of start-of-packet byte or byte sequence. This is transmitted prior to the data in order to "train" the receiver AGC to the signal level (remember it has AGC and is responding to noise until now) and to notify the micro that data is coming. So you might transmit a series of five 0xF0 bytes, with some time in between. The first one or two will maybe be botched by the Rx RF module as it tunes its AGC. Then the next three or so will make it through and the microcontroller will recognize that this is a start of packet (discarding these). Then the real data starts... hopefully followed by a checksum or CRC for validation. This might sound complicated but it is just about the absolute minimum that must be done on a noisy link.
You may need to do something similar, but if you choose your threshold wisely, you won't need to deal with noise/garbage data in the idle condition. You should still consider some kind of start-of-packet and a checksum.