esphome/esphome/helpers.py
Otto Winter 8e75980ebd
Cleanup dashboard JS (#491)
* Cleanup dashboard JS

* Add vscode

* Save start_mark/end_mark

* Updates

* Updates

* Remove need for cv.nameable

It's a bit hacky but removes so much bloat from integrations

* Add enum helper

* Document APIs, and Improvements

* Fixes

* Fixes

* Update PULL_REQUEST_TEMPLATE.md

* Updates

* Updates

* Updates
2019-04-22 21:56:30 +02:00

189 lines
4.7 KiB
Python

from __future__ import print_function
import codecs
import logging
import os
from esphome.py_compat import char_to_byte, text_type
_LOGGER = logging.getLogger(__name__)
def ensure_unique_string(preferred_string, current_strings):
test_string = preferred_string
current_strings_set = set(current_strings)
tries = 1
while test_string in current_strings_set:
tries += 1
test_string = u"{}_{}".format(preferred_string, tries)
return test_string
def indent_all_but_first_and_last(text, padding=u' '):
lines = text.splitlines(True)
if len(lines) <= 2:
return text
return lines[0] + u''.join(padding + line for line in lines[1:-1]) + lines[-1]
def indent_list(text, padding=u' '):
return [padding + line for line in text.splitlines()]
def indent(text, padding=u' '):
return u'\n'.join(indent_list(text, padding))
# From https://stackoverflow.com/a/14945195/8924614
def cpp_string_escape(string, encoding='utf-8'):
def _should_escape(byte): # type: (int) -> bool
if not 32 <= byte < 127:
return True
if byte in (char_to_byte('\\'), char_to_byte('"')):
return True
return False
if isinstance(string, text_type):
string = string.encode(encoding)
result = ''
for character in string:
character = char_to_byte(character)
if _should_escape(character):
result += '\\%03o' % character
else:
result += chr(character)
return '"' + result + '"'
def color(the_color, message=''):
from colorlog.escape_codes import escape_codes, parse_colors
if not message:
res = parse_colors(the_color)
else:
res = parse_colors(the_color) + message + escape_codes['reset']
return res
def run_system_command(*args):
import subprocess
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
rc = p.returncode
return rc, stdout, stderr
def mkdir_p(path):
import errno
try:
os.makedirs(path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def is_ip_address(host):
parts = host.split('.')
if len(parts) != 4:
return False
try:
for p in parts:
int(p)
return True
except ValueError:
return False
def _resolve_with_zeroconf(host):
from esphome.core import EsphomeError
from esphome.zeroconf import Zeroconf
try:
zc = Zeroconf()
except Exception:
raise EsphomeError("Cannot start mDNS sockets, is this a docker container without "
"host network mode?")
try:
info = zc.resolve_host(host + '.')
except Exception as err:
raise EsphomeError("Error resolving mDNS hostname: {}".format(err))
finally:
zc.close()
if info is None:
raise EsphomeError("Error resolving address with mDNS: Did not respond. "
"Maybe the device is offline.")
return info
def resolve_ip_address(host):
from esphome.core import EsphomeError
import socket
try:
ip = socket.gethostbyname(host)
except socket.error as err:
if host.endswith('.local'):
ip = _resolve_with_zeroconf(host)
else:
raise EsphomeError("Error resolving IP address: {}".format(err))
return ip
def get_bool_env(var, default=False):
return bool(os.getenv(var, default))
def is_hassio():
return get_bool_env('ESPHOME_IS_HASSIO')
def copy_file_if_changed(src, dst):
src_text = read_file(src)
if os.path.isfile(dst):
dst_text = read_file(dst)
else:
dst_text = None
if src_text == dst_text:
return
write_file(dst, src_text)
def read_file(path):
try:
with codecs.open(path, 'r', encoding='utf-8') as f_handle:
return f_handle.read()
except OSError:
from esphome.core import EsphomeError
raise EsphomeError(u"Could not read file at {}".format(path))
def write_file(path, text):
try:
mkdir_p(os.path.dirname(path))
with codecs.open(path, 'w+', encoding='utf-8') as f_handle:
f_handle.write(text)
except OSError:
from esphome.core import EsphomeError
raise EsphomeError(u"Could not write file at {}".format(path))
def write_file_if_changed(text, dst):
src_content = None
if os.path.isfile(dst):
src_content = read_file(dst)
if src_content != text:
write_file(dst, text)
def list_starts_with(list_, sub):
return len(sub) <= len(list_) and all(list_[i] == x for i, x in enumerate(sub))