_run_idedata raises EsphomeError() with no message, so the warning
shows 'unavailable ()' which looks like a bug. Use a generic fallback
explanation when str(exc) is empty.
_decode_pc shells out to PlatformIO via _run_idedata; without a
populated build dir for the device that subprocess fails for every
PC/BT line in a crash dump. Disable decoding after the first
EsphomeError (per logs session) and emit a single user-facing warning
instead of retrying on every line.
Also rename the helper to _LogLineProcessor since it now owns the
per-session decode-enabled state, not just the decode call.
When 'esphome logs' processes a crash backtrace from the device,
process_stacktrace -> _decode_pc -> _run_idedata can raise
EsphomeError if the local build dir hasn't been populated (e.g. the
device was flashed from a different machine). on_log runs inside an
asyncio protocol callback, so the unhandled exception triggers
'Fatal error: protocol.data_received() call failed.', the loop tears
the connection down, and ReconnectLogic immediately reconnects. The
device replays the same crash trace and we loop forever.
Wrap the per-line decode in a helper that swallows EsphomeError so
the connection stays up. Also covered with unit tests for the new
helper.