Async SerialPort Wrapper
_port.Encoding.GetBytes(_port.ReadExisting())


If you want to work with byte[], then your data should never appear as string, even temporarily, because some byte sequences are likely going to be invalid in your encoding.

I believe you should be able to use the byte[] overload of Read() for this. (Though switching to byte[] and async methods of the BaseStream is probably a better choice in the long run.)



Your class is schizophrenic about whether it wants to use string or byte[] (the observables use byte[], Write() uses string). You should figure out which choice makes more sense and stick to it.



What is the purpose of DataTx? I think that being able to read what you have written is not commonly needed.



I realize that Tx and Rx are abbreviations used in networking, but I find them confusing. Are you sure users of this library will immediately understand them? If not, you should rename the properties.



Boolean
String


It's common to write those types in their keyword form: bool, string.



~ComPort() {
    Dispose(false);
}


You don't have any unmanaged resources, so Dispose(false) basically doesn't do anything. But this means there is no reason for this class to have a finalizer.

The Dispose Pattern makes sense when you're writing a class that is going to be inherited. But since your class is sealed (nice, most people don't bother with that), I think there is also no reason to have the Dispose(bool) overload, just a single Dispose() method will be enough.