Semaphore has a state protected by atomic operations, meanwhile the condition variable (CV) does not have its own state and is not even protected (the usual assumption is that the program has its own, more complicated shared state than just an integer and thus needs to maintain it "manually").
The correct use of CV requires that both signal and wait operations are protected (surrounded by the associated mutex locking), otherwise the waiting thread may miss the signalling. So the program needs to ensure the proper locking sequence on CVs.
Meanwhile semaphore operations are hidden from developer, and the code is simpler and cannot go wrong in ways CVs can, but it also maintains very simple/small shared state with very specific operations.