# Path: notify.py
# class Notify():
#     """Send an Email to notify user"""
#     def send(self, msg):
#         self.logger = logging.getLogger()
#         self.msg = msg
#         threading.Thread(target=self._send).start()
# 
#     def _send(self):
#         try:
#             config = configparser.ConfigParser()
#             config.read('notify.ini')
#             # load user defined email settings
#             user = config.get('authentication', 'user', fallback=None)
#             password = config.get('authentication', 'password', fallback=None)
#             server = config.get('authentication', 'server', fallback=None)
#             port = config.getint('authentication', 'port', fallback=465)
#             to_addr = config.get('header', 'to_address', fallback=None)
#             subject = config.get('header', 'subject', fallback='Smoopi notification')
# 
#         except Exception as err:
#             self.logger.error('Notify: notify.ini file errors: {}'.format(err))
#             return False
# 
#         if user is None:
#             self.logger.error('Notify: no user specified')
#             return False
#         if password is None:
#             self.logger.error('Notify: no password specified')
#             return False
#         if server is None:
#             self.logger.error('Notify: no server specified')
#             return False
#         if to_addr is None:
#             self.logger.error('Notify: no to address specified')
#             return False
# 
#         body = '{}\n'.format(self.msg)
# 
#         email_text = """\
# From: %s
# To: %s
# Subject: %s
# 
# %s
# """ % (user, to_addr, subject, body)
# 
#         try:
#             server = smtplib.SMTP_SSL(server, port)
#             server.ehlo()
#             server.login(user, password)
#             server.sendmail(user, to_addr, email_text)
#             server.close()
#             return True
# 
#         except Exception as ex:
#             self.logger.error('Notify: Failed to send email: {}'.format(ex))
#             return False


import threading
import asyncio
import aiofiles
import logging
import functools
import sys
import re
import os
import traceback
import serial.tools.list_ports
import subprocess
import socket
import time
import libs.serial_asyncio.serial_asyncio
    import datetime
from notify import Notify
        self.cnt = 0
        self.is_net = is_net
        self._paused = False
        self._drain_waiter = None
        self._connection_lost = False
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport
        self.log.debug('SerialConnection: port opened: {}'.format(transport))
        if self.is_net:
            # we don't want to buffer the entire file on the host
            transport.get_extra_info('socket').setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2048)
            self.log.info("SerialConnection: Setting net tx buf to 2048")
            # for net we want to limit how much we queue up otherwise the whole file gets queued
            # this also gives us more progress more often
            transport.set_write_buffer_limits(high=1024, low=256)
            self.log.info('SerialConnection: Buffer limits: {} - {}'.format(transport._high_water, transport._low_water))
        else:
            transport.set_write_buffer_limits(high=1024, low=64)
            self.log.info('SerialConnection: Buffer limits: {} - {}'.format(transport._high_water, transport._low_water))
            # transport.serial.rts = False  # You can manipulate Serial object via transport
            transport.serial.reset_input_buffer()
            transport.serial.reset_output_buffer()
            try:
                transport.serial.set_low_latency_mode(True)
            except Exception as e:
                self.log.warning("Failed to set low latency mode: {}".format(e))
            # print(transport.serial)


# Path: notify.py
# class Notify():
#     """Send an Email to notify user"""
#     def send(self, msg):
#         self.logger = logging.getLogger()
#         self.msg = msg
#         threading.Thread(target=self._send).start()
# 
#     def _send(self):
#         try:
#             config = configparser.ConfigParser()
#             config.read('notify.ini')
#             # load user defined email settings
#             user = config.get('authentication', 'user', fallback=None)
#             password = config.get('authentication', 'password', fallback=None)
#             server = config.get('authentication', 'server', fallback=None)
#             port = config.getint('authentication', 'port', fallback=465)
#             to_addr = config.get('header', 'to_address', fallback=None)
#             subject = config.get('header', 'subject', fallback='Smoopi notification')
# 
#         except Exception as err:
#             self.logger.error('Notify: notify.ini file errors: {}'.format(err))
#             return False
# 
#         if user is None:
#             self.logger.error('Notify: no user specified')
#             return False
#         if password is None:
#             self.logger.error('Notify: no password specified')
#             return False
#         if server is None:
#             self.logger.error('Notify: no server specified')
#             return False
#         if to_addr is None:
#             self.logger.error('Notify: no to address specified')
#             return False
# 
#         body = '{}\n'.format(self.msg)
# 
#         email_text = """\
# From: %s
# To: %s
# Subject: %s
# 
# %s
# """ % (user, to_addr, subject, body)
# 
#         try:
#             server = smtplib.SMTP_SSL(server, port)
#             server.ehlo()
#             server.login(user, password)
#             server.sendmail(user, to_addr, email_text)
#             server.close()
#             return True
# 
#         except Exception as ex:
#             self.logger.error('Notify: Failed to send email: {}'.format(ex))
#             return False


# Path: comms.py
import threading
import asyncio
import aiofiles
import logging
import functools
import sys
import re
import os
import traceback
import serial.tools.list_ports
import subprocess
import socket
import time
import libs.serial_asyncio.serial_asyncio
    import datetime
from notify import Notify

        self.cnt = 0
        self.is_net = is_net
        self._paused = False
        self._drain_waiter = None
        self._connection_lost = False
        self.transport = None

    def connection_made(self, transport):
        self.transport = transport
        self.log.debug('SerialConnection: port opened: {}'.format(transport))
        if self.is_net:
            # we don't want to buffer the entire file on the host
            transport.get_extra_info('socket').setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2048)
            self.log.info("SerialConnection: Setting net tx buf to 2048")
            # for net we want to limit how much we queue up otherwise the whole file gets queued
            # this also gives us more progress more often
            transport.set_write_buffer_limits(high=1024, low=256)
            self.log.info('SerialConnection: Buffer limits: {} - {}'.format(transport._high_water, transport._low_water))
        else:
            transport.set_write_buffer_limits(high=1024, low=64)
            self.log.info('SerialConnection: Buffer limits: {} - {}'.format(transport._high_water, transport._low_water))
            # transport.serial.rts = False  # You can manipulate Serial object via transport
            transport.serial.reset_input_buffer()
            transport.serial.reset_output_buffer()
            try:
                transport.serial.set_low_latency_mode(True)
            except Exception as e:
                self.log.warning("Failed to set low latency mode: {}".format(e))
            # print(transport.serial)


    def flush_queue(self):