Among several aspects of the question, I'll cover only protection against replay of commands.
A common technique (among several) is to have commands tied to a nonce, that somewhat is accepted only once by the slave device receiving the command. The nonce is included in the input of a MAC or public-key signature algorithm that protects the integrity of the command.
When two-way communication is possible, a nonce can simply be a true random value wide-enough to most likely not repeat (say, 16-byte), generated by the slave device and sent to the master before it sends a command. The slave then receives the command, checks the MAC or signature included in the command (prepared on data including the nonce, as a prefix of the data in the actual command), and executes the command only if the MAC or signature checks. The slave then no longer accepts to execute another command until it has generated another nonce.
This is safe from the standpoint of pure replay. However an adversary may be content to defer execution of a command (rather than execute it a second time). Think of a garage door: an adversary waits for the home owner returning home and sending an open command; the adversary captures that command until the middle of the CRC at the end, and starting from that instant jams the radio channel. The command is ignored by the slave for wrong CRC, and does not get executed. Long after the attacker stops the jamming, then retransmits the command with recomputed CRC; abracadabra the door opens! Amazingly, some complex secure channel protocols put no time limit on how much an active adversary can delay a frame (perhaps inserting dummy requests for repetition to keep some link active), and are vulnerable to that attack. There's a simple countermeasure: we can put a time limit to the validity of a nonce, like seconds, enforced by the slave, counted from the sending of the nonce; and the nonce needs to be unpredictable (rather than only unique) to block some variants of the attack.
This is fine, but the nonce requires two extra frames (to the slave asking for the nonce; from the slave with the nonce). One option to reduce at least the number of overhead frames is to embed a fresh nonce in every frame sent, applicable to the next frame if received within delay; so that in a burst of commands, the overhead is two initial frames, plus the size of the nonces added to other frames. With great care, that later overhead can be eliminated using precise conventions on how the nonce evolves when there is authenticated activity.
Caution: the problem of making the nonce unpredictable, or even not repeating itself, is notoriously difficult if the adversary has access to the power supply of a slave device with no reliable TRNG (that was the situation in early Smart Cards). The solution of enciphering a counter held in EEPROM with a local secret key superficially seems to work (and even allow to use a nonce twice narrower with increased assurance against reuse); but there are the issues of making a counter that does not go backward on power loss during change; limited endurance of EEPROM to repeated writes to the same location; and the basic difficulty of keeping a secret key secret despite side-channels.