From 1e12cba176e9372a4b91b34687e02bf1de6b492b Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Thu, 3 Jan 2019 16:05:33 +0100 Subject: [PATCH] Fixes for Python 3 Compatability (#297) --- esphomeyaml/__main__.py | 8 ++++++-- esphomeyaml/api/client.py | 21 ++++++++++++--------- esphomeyaml/config.py | 2 +- esphomeyaml/dashboard/dashboard.py | 14 +++++++++++--- esphomeyaml/espota2.py | 16 ++++++++++++---- esphomeyaml/pins.py | 2 +- esphomeyaml/py_compat.py | 21 +++++++++++++++++++++ 7 files changed, 64 insertions(+), 20 deletions(-) diff --git a/esphomeyaml/__main__.py b/esphomeyaml/__main__.py index 2009e2d28f..7aa274e614 100644 --- a/esphomeyaml/__main__.py +++ b/esphomeyaml/__main__.py @@ -16,7 +16,7 @@ from esphomeyaml.const import CONF_BAUD_RATE, CONF_ESPHOMEYAML, CONF_LOGGER, CON from esphomeyaml.core import CORE, EsphomeyamlError from esphomeyaml.cpp_generator import Expression, RawStatement, add, statement from esphomeyaml.helpers import color, indent -from esphomeyaml.py_compat import safe_input, text_type +from esphomeyaml.py_compat import safe_input, text_type, IS_PY2 from esphomeyaml.storage_json import StorageJSON, esphomeyaml_storage_path, \ start_update_check_thread, storage_path from esphomeyaml.util import run_external_command, safe_print @@ -110,7 +110,11 @@ def run_miniterm(config, port): except serial.SerialException: _LOGGER.error("Serial port closed!") return - line = raw.replace('\r', '').replace('\n', '') + if IS_PY2: + line = raw.replace('\r', '').replace('\n', '') + else: + line = raw.replace(b'\r', b'').replace(b'\n', b'').decode('utf8', + 'backslashreplace') time = datetime.now().time().strftime('[%H:%M:%S]') message = time + line safe_print(message) diff --git a/esphomeyaml/api/client.py b/esphomeyaml/api/client.py index 2b2987afde..53608a3082 100644 --- a/esphomeyaml/api/client.py +++ b/esphomeyaml/api/client.py @@ -14,7 +14,7 @@ import esphomeyaml.api.api_pb2 as pb from esphomeyaml.const import CONF_PASSWORD, CONF_PORT from esphomeyaml.core import EsphomeyamlError from esphomeyaml.helpers import resolve_ip_address, indent, color -from esphomeyaml.py_compat import text_type +from esphomeyaml.py_compat import text_type, IS_PY2, byte, char, format_bytes from esphomeyaml.util import safe_print _LOGGER = logging.getLogger(__name__) @@ -67,16 +67,16 @@ MESSAGE_TYPE_TO_PROTO = { def _varuint_to_bytes(value): if value <= 0x7F: - return chr(value) + return byte(value) ret = bytes() while value: temp = value & 0x7F value >>= 7 if value: - ret += chr(temp | 0x80) + ret += byte(temp | 0x80) else: - ret += chr(temp) + ret += byte(temp) return ret @@ -85,7 +85,7 @@ def _bytes_to_varuint(value): result = 0 bitpos = 0 for c in value: - val = ord(c) + val = char(c) result |= (val & 0x7F) << bitpos bitpos += 7 if (val & 0x80) == 0: @@ -245,7 +245,7 @@ class APIClient(threading.Thread): if self._socket is None: raise APIConnectionError("Socket closed") - _LOGGER.debug("Write: %s", ' '.join('{:02X}'.format(ord(x)) for x in data)) + _LOGGER.debug("Write: %s", format_bytes(data)) with self._socket_write_lock: try: self._socket.sendall(data) @@ -263,7 +263,10 @@ class APIClient(threading.Thread): encoded = msg.SerializeToString() _LOGGER.debug("Sending %s:\n%s", type(msg), indent(text_type(msg))) - req = chr(0x00) + if IS_PY2: + req = chr(0x00) + else: + req = bytes([0]) req += _varuint_to_bytes(len(encoded)) req += _varuint_to_bytes(message_type) req += encoded @@ -358,7 +361,7 @@ class APIClient(threading.Thread): def _recv_varint(self): raw = bytes() - while not raw or ord(raw[-1]) & 0x80: + while not raw or char(raw[-1]) & 0x80: raw += self._recv(1) return _bytes_to_varuint(raw) @@ -367,7 +370,7 @@ class APIClient(threading.Thread): return # Preamble - if ord(self._recv(1)[0]) != 0x00: + if char(self._recv(1)[0]) != 0x00: raise APIConnectionError("Invalid preamble") length = self._recv_varint() diff --git a/esphomeyaml/config.py b/esphomeyaml/config.py index 7be8d19908..0402a4d66f 100644 --- a/esphomeyaml/config.py +++ b/esphomeyaml/config.py @@ -439,7 +439,7 @@ def load_config(): try: config = yaml_util.load_yaml(CORE.config_path) except OSError: - raise EsphomeyamlError(u"Could not read configuration file at {}".format(CORE.config_path)) + raise EsphomeyamlError(u"Invalid YAML at {}".format(CORE.config_path)) CORE.raw_config = config config = substitutions.do_substitution_pass(config) core_config.preload_core_config(config) diff --git a/esphomeyaml/dashboard/dashboard.py b/esphomeyaml/dashboard/dashboard.py index d21a7e4664..3c01e6fdcf 100644 --- a/esphomeyaml/dashboard/dashboard.py +++ b/esphomeyaml/dashboard/dashboard.py @@ -26,6 +26,7 @@ import tornado.websocket from esphomeyaml import const from esphomeyaml.__main__ import get_serial_ports from esphomeyaml.helpers import mkdir_p, run_system_command +from esphomeyaml.py_compat import IS_PY2 from esphomeyaml.storage_json import EsphomeyamlStorageJSON, StorageJSON, \ esphomeyaml_storage_path, ext_storage_path from esphomeyaml.util import shlex_quote @@ -77,7 +78,13 @@ class EsphomeyamlCommandWebSocket(tornado.websocket.WebSocketHandler): def redirect_stream(self): while True: try: - data = yield self.proc.stdout.read_until_regex('[\n\r]') + if IS_PY2: + reg = '[\n\r]' + else: + reg = b'[\n\r]' + data = yield self.proc.stdout.read_until_regex(reg) + if not IS_PY2: + data = data.decode('utf-8', 'backslashreplace') except tornado.iostream.StreamClosedError: break try: @@ -166,7 +173,8 @@ class SerialPortRequestHandler(BaseHandler): desc = split_desc[0] data.append({'port': port, 'desc': desc}) data.append({'port': 'OTA', 'desc': 'Over-The-Air'}) - self.write(json.dumps(sorted(data, reverse=True))) + data.sort(key=lambda x: x['port'], reverse=True) + self.write(json.dumps(data)) class WizardRequestHandler(BaseHandler): @@ -390,7 +398,7 @@ class EditRequestHandler(BaseHandler): self.set_status(401) return - with open(os.path.join(CONFIG_DIR, configuration), 'w') as f: + with open(os.path.join(CONFIG_DIR, configuration), 'wb') as f: f.write(self.request.body) self.set_status(200) return diff --git a/esphomeyaml/espota2.py b/esphomeyaml/espota2.py index cda59d5b63..f329c07949 100755 --- a/esphomeyaml/espota2.py +++ b/esphomeyaml/espota2.py @@ -7,6 +7,7 @@ import time from esphomeyaml.core import EsphomeyamlError from esphomeyaml.helpers import resolve_ip_address, is_ip_address +from esphomeyaml.py_compat import IS_PY2 RESPONSE_OK = 0 RESPONSE_REQUEST_AUTH = 1 @@ -125,10 +126,17 @@ def check_error(data, expect): def send_check(sock, data, msg): try: - if isinstance(data, (list, tuple)): - data = ''.join([chr(x) for x in data]) - elif isinstance(data, int): - data = chr(data) + if IS_PY2: + if isinstance(data, (list, tuple)): + data = ''.join([chr(x) for x in data]) + elif isinstance(data, int): + data = chr(data) + else: + if isinstance(data, (list, tuple)): + data = bytes(data) + elif isinstance(data, int): + data = bytes([data]) + sock.sendall(data) except socket.error as err: raise OTAError("Error sending {}: {}".format(msg, err)) diff --git a/esphomeyaml/pins.py b/esphomeyaml/pins.py index e718bb03c9..9a99f9ad7e 100644 --- a/esphomeyaml/pins.py +++ b/esphomeyaml/pins.py @@ -63,7 +63,7 @@ FLASH_SIZE_1_MB = 2**20 FLASH_SIZE_512_KB = FLASH_SIZE_1_MB // 2 FLASH_SIZE_2_MB = 2 * FLASH_SIZE_1_MB FLASH_SIZE_4_MB = 4 * FLASH_SIZE_1_MB -FLASH_SIZE_16_MB = 4 * FLASH_SIZE_1_MB +FLASH_SIZE_16_MB = 16 * FLASH_SIZE_1_MB ESP8266_FLASH_SIZES = { 'd1': FLASH_SIZE_4_MB, diff --git a/esphomeyaml/py_compat.py b/esphomeyaml/py_compat.py index c3051fc19f..5e70766c46 100644 --- a/esphomeyaml/py_compat.py +++ b/esphomeyaml/py_compat.py @@ -23,3 +23,24 @@ else: string_types = (str,) integer_types = (int,) binary_type = bytes + + +def byte(val): + if IS_PY2: + return chr(val) + else: + return bytes([val]) + + +def char(val): + if IS_PY2: + return ord(val) + else: + return val + + +def format_bytes(val): + if IS_PY2: + return ' '.join('{:02X}'.format(ord(x)) for x in val) + else: + return ' '.join('{:02X}'.format(x) for x in val)