1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-05 01:21:50 +00:00

Compare commits

..

20 Commits

Author SHA1 Message Date
Otto Winter
f7671f0c90 Bump version to 1.8.2 2018-10-07 17:01:15 +02:00
Otto Winter
639b97ccb2 WiFi: Add power save mode option (#150)
* WiFi: Add power save mode option

* Lint
2018-10-07 16:52:14 +02:00
Otto Winter
0374b3a0b3 Fix component loader value error (#149)
* Print better error message when loader fails with ValueError

* Improve

* Improve
2018-10-07 14:38:22 +02:00
Otto Winter
7ce753b76f Docker default to starting dashboard (#143) 2018-10-04 19:01:57 +02:00
Otto Winter
05a1089ed2 Bump platformio-espressif32 to 1.4.0 (#142) 2018-10-04 19:01:24 +02:00
Otto Winter
71947bb6ac Fix using unicode in lambdas (#141)
https://github.com/OttoWinter/esphomeyaml/issues/128#issuecomment-425777989
2018-10-04 19:01:13 +02:00
Otto Winter
ef54e33b70 Add clean MQTT button to dashboard (#139) 2018-10-04 19:01:02 +02:00
Otto Winter
12f20fc3cf Fix serial monitor opening when logger disabled (#138)
Fixes #137
2018-10-04 19:00:51 +02:00
Otto Winter
ffdcddc18e Add SSD1306 64x48 display (#136) 2018-09-29 14:50:14 +02:00
Otto Winter
85d70eb5a0 Auto-Update esphomelib dev version (#134)
* Auto-Update esphomelib dev version

* Lint
2018-09-29 14:50:04 +02:00
Otto Winter
ffb793177a Enable Travis Tests (#133) 2018-09-28 19:34:28 +02:00
Otto Winter
d3f2fab88a Fix SSD1306 lambda (#132)
As per #128
2018-09-28 18:17:22 +02:00
Otto Winter
0fa52d0ce6 Fix MQTT discovery enabled when discovery_retain in config (#131) 2018-09-27 16:34:11 +02:00
Otto Winter
cf264a2743 Fix binary sensor heartbeat not working (#130) 2018-09-27 16:34:02 +02:00
Otto Winter
433b605bef Bump version to 1.8.1 2018-09-26 19:00:41 +02:00
Otto Winter
6e60c6493a Use cache for HassIO add-on images 2018-09-26 18:59:39 +02:00
Otto Winter
4e63bc96d5 Fix main docker image missing platformio 2018-09-26 18:39:55 +02:00
Otto Winter
ce4b339d16 Split up BLE tests into new file 2018-09-26 18:39:41 +02:00
Otto Winter
ab6d293d0d Fix docker installs using old platformio version (#125)
* Fix min platformio version and update requirements

* Remove unnecessary requirements from travis
2018-09-27 01:14:51 +09:00
Otto Winter
5e5137960d Limit upload speed to 115200 (#122)
* Limit upload speed to 115200

* Lint
2018-09-26 01:27:47 +09:00
25 changed files with 389 additions and 121 deletions

View File

@@ -47,11 +47,16 @@ pylint:
script:
- pylint esphomeyaml
test:
test1:
<<: *test
script:
- esphomeyaml tests/test1.yaml compile
test2:
<<: *test
script:
- esphomeyaml tests/test2.yaml compile
.build-hassio: &build-hassio
<<: *docker-builder
stage: build
@@ -79,6 +84,10 @@ test:
- echo "Publishing version ${version}"
- docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
- docker pull "${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- |
docker tag \
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- |
docker tag \
"${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
@@ -87,6 +96,7 @@ test:
docker tag \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- docker push "${CI_REGISTRY}/ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"

View File

@@ -2,9 +2,19 @@ sudo: false
language: python
python:
- "2.7"
install:
- pip install -r requirements.txt
- pip install tornado esptool flake8==3.5.0 pylint==1.8.4 tzlocal pillow
script:
- flake8 esphomeyaml
- pylint esphomeyaml
jobs:
include:
- name: "Lint"
install:
- pip install -r requirements.txt
- pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow
script:
- flake8 esphomeyaml
- pylint esphomeyaml
- name: "Test"
install:
- pip install -e .
- pip install tzlocal pillow
script:
- esphomeyaml tests/test1.yaml compile
- esphomeyaml tests/test2.yaml compile

View File

@@ -10,9 +10,8 @@ EXPOSE 6123
VOLUME /config
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN pip install --no-cache-dir -r requirements.txt && \
pip install --no-cache-dir tornado esptool
RUN pip install --no-cache-dir --no-binary :all: platformio && \
platformio settings set enable_telemetry No
COPY docker/platformio.ini /usr/src/app/
RUN platformio settings set enable_telemetry No && \
@@ -20,7 +19,8 @@ RUN platformio settings set enable_telemetry No && \
COPY . .
RUN pip install --no-cache-dir -e . && \
pip install --no-cache-dir tzlocal
pip install --no-cache-dir tzlocal pillow
WORKDIR /config
ENTRYPOINT ["esphomeyaml"]
CMD ["/config", "dashboard"]

View File

@@ -3,4 +3,4 @@ FROM python:2.7
COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt && \
pip install flake8==3.5.0 pylint==1.8.4 tzlocal pillow
pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow

View File

@@ -13,23 +13,15 @@ from esphomeyaml.const import CONF_BAUD_RATE, CONF_BUILD_PATH, CONF_DOMAIN, CONF
CONF_HOSTNAME, CONF_LOGGER, CONF_MANUAL_IP, CONF_NAME, CONF_STATIC_IP, CONF_USE_CUSTOM_CODE, \
CONF_WIFI, ESP_PLATFORM_ESP8266
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, _EXPRESSIONS, add, \
add_job, color, flush_tasks, indent, quote, statement
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, \
_EXPRESSIONS, add, \
add_job, color, flush_tasks, indent, quote, statement, relative_path
_LOGGER = logging.getLogger(__name__)
PRE_INITIALIZE = ['esphomeyaml', 'logger', 'wifi', 'ota', 'mqtt', 'web_server', 'i2c']
def get_name(config):
return config[CONF_ESPHOMEYAML][CONF_NAME]
def get_base_path(config):
build_path = config[CONF_ESPHOMEYAML].get(CONF_BUILD_PATH, get_name(config))
return os.path.join(os.path.dirname(core.CONFIG_PATH), build_path)
def get_serial_ports():
# from https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports.py
from serial.tools.list_ports import comports
@@ -99,7 +91,12 @@ def run_platformio(*cmd, **kwargs):
def run_miniterm(config, port, escape=False):
import serial
baud_rate = config.get(CONF_LOGGER, {}).get(CONF_BAUD_RATE, 115200)
if CONF_LOGGER not in config:
_LOGGER.info("Logger is not enabled. Not starting UART logs.")
return
baud_rate = config['logger'][CONF_BAUD_RATE]
if baud_rate == 0:
_LOGGER.info("UART logging is disabled (baud_rate=0). Not starting UART logs.")
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
with serial.Serial(port, baudrate=baud_rate) as ser:
@@ -148,17 +145,19 @@ def write_cpp(config):
exp = exp.rhs
all_code.append(unicode(statement(exp)))
writer.write_platformio_project(config, get_base_path(config))
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
writer.write_platformio_project(config, build_path)
code_s = indent('\n'.join(line.rstrip() for line in all_code))
cpp_path = os.path.join(get_base_path(config), 'src', 'main.cpp')
cpp_path = os.path.join(build_path, 'src', 'main.cpp')
writer.write_cpp(code_s, cpp_path)
return 0
def compile_program(args, config):
_LOGGER.info("Compiling app...")
command = ['platformio', 'run', '-d', get_base_path(config)]
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
command = ['platformio', 'run', '-d', build_path]
if args.verbose:
command.append('-v')
return run_platformio(*command)
@@ -177,8 +176,8 @@ def get_upload_host(config):
def upload_using_esptool(config, port):
import esptool
name = get_name(config)
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
path = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin')
# pylint: disable=protected-access
return run_platformio('esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
'--chip', 'esp8266', '--port', port, 'write_flash', '0x0',
@@ -187,13 +186,14 @@ def upload_using_esptool(config, port):
def upload_program(config, args, port):
_LOGGER.info("Uploading binary...")
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
# if upload is to a serial port use platformio, otherwise assume ota
serial_port = port.startswith('/') or port.startswith('COM')
if port != 'OTA' and serial_port:
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266 and args.use_esptoolpy:
return upload_using_esptool(config, port)
command = ['platformio', 'run', '-d', get_base_path(config),
command = ['platformio', 'run', '-d', build_path,
'-t', 'upload', '--upload-port', port]
if args.verbose:
command.append('-v')
@@ -213,7 +213,7 @@ def upload_program(config, args, port):
from esphomeyaml.components import ota
from esphomeyaml import espota
bin_file = os.path.join(get_base_path(config), '.pioenvs', get_name(config), 'firmware.bin')
bin_file = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin')
if args.host_port is not None:
host_port = args.host_port
else:
@@ -451,6 +451,8 @@ def parse_args(argv):
default=6052)
dashboard.add_argument("--password", help="The optional password to require for all requests.",
type=str, default='')
dashboard.add_argument("--open-ui", help="Open the dashboard UI in a browser.",
action='store_true')
return parser.parse_args(argv[1:])

View File

@@ -33,7 +33,7 @@ DelayedOffFilter = binary_sensor_ns.DelayedOffFilter
HeartbeatFilter = binary_sensor_ns.HeartbeatFilter
MQTTBinarySensorComponent = binary_sensor_ns.MQTTBinarySensorComponent
FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA]
FILTER_KEYS = [CONF_INVERT, CONF_DELAYED_ON, CONF_DELAYED_OFF, CONF_LAMBDA, CONF_HEARTBEAT]
FILTERS_SCHEMA = vol.All(cv.ensure_list, [vol.All({
vol.Optional(CONF_INVERT): None,

View File

@@ -4,8 +4,10 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.components import display
from esphomeyaml.components.display import ssd1306_spi
from esphomeyaml.const import CONF_ADDRESS, CONF_EXTERNAL_VCC, CONF_ID, CONF_MODEL, CONF_RESET_PIN
from esphomeyaml.helpers import App, Pvariable, add, gpio_output_pin_expression
from esphomeyaml.const import CONF_ADDRESS, CONF_EXTERNAL_VCC, CONF_ID, \
CONF_MODEL, CONF_RESET_PIN, CONF_LAMBDA
from esphomeyaml.helpers import App, Pvariable, add, \
gpio_output_pin_expression, process_lambda
DEPENDENCIES = ['i2c']
@@ -32,6 +34,11 @@ def to_code(config):
add(ssd.set_external_vcc(config[CONF_EXTERNAL_VCC]))
if CONF_ADDRESS in config:
add(ssd.set_address(config[CONF_ADDRESS]))
if CONF_LAMBDA in config:
for lambda_ in process_lambda(config[CONF_LAMBDA],
[(display.DisplayBufferRef, 'it')]):
yield
add(ssd.set_writer(lambda_))
display.setup_display(ssd, config)

View File

@@ -4,9 +4,11 @@ import esphomeyaml.config_validation as cv
from esphomeyaml import pins
from esphomeyaml.components import display
from esphomeyaml.components.spi import SPIComponent
from esphomeyaml.const import CONF_CS_PIN, CONF_DC_PIN, CONF_EXTERNAL_VCC, CONF_ID, CONF_MODEL, \
CONF_RESET_PIN, CONF_SPI_ID
from esphomeyaml.helpers import App, Pvariable, add, get_variable, gpio_output_pin_expression
from esphomeyaml.const import CONF_CS_PIN, CONF_DC_PIN, CONF_EXTERNAL_VCC, \
CONF_ID, CONF_MODEL, \
CONF_RESET_PIN, CONF_SPI_ID, CONF_LAMBDA
from esphomeyaml.helpers import App, Pvariable, add, get_variable, \
gpio_output_pin_expression, process_lambda
DEPENDENCIES = ['spi']
@@ -16,9 +18,11 @@ MODELS = {
'SSD1306_128X32': display.display_ns.SSD1306_MODEL_128_32,
'SSD1306_128X64': display.display_ns.SSD1306_MODEL_128_64,
'SSD1306_96X16': display.display_ns.SSD1306_MODEL_96_16,
'SSD1306_64X48': display.display_ns.SSD1306_MODEL_64_48,
'SH1106_128X32': display.display_ns.SH1106_MODEL_128_32,
'SH1106_128X64': display.display_ns.SH1106_MODEL_128_64,
'SH1106_96X16': display.display_ns.SH1106_MODEL_96_16,
'SH1106_64X48': display.display_ns.SH1106_MODEL_64_48,
}
SSD1306_MODEL = vol.All(vol.Upper, vol.Replace(' ', '_'), cv.one_of(*MODELS))
@@ -52,6 +56,11 @@ def to_code(config):
add(ssd.set_reset_pin(reset))
if CONF_EXTERNAL_VCC in config:
add(ssd.set_external_vcc(config[CONF_EXTERNAL_VCC]))
if CONF_LAMBDA in config:
for lambda_ in process_lambda(config[CONF_LAMBDA],
[(display.DisplayBufferRef, 'it')]):
yield
add(ssd.set_writer(lambda_))
display.setup_display(ssd, config)

View File

@@ -35,7 +35,7 @@ LogComponent = esphomelib_ns.LogComponent
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(LogComponent),
vol.Optional(CONF_BAUD_RATE): cv.positive_int,
vol.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int,
vol.Optional(CONF_TX_BUFFER_SIZE): cv.validate_bytes,
vol.Optional(CONF_LEVEL): is_log_level,
vol.Optional(CONF_LOGS): vol.Schema({

View File

@@ -100,7 +100,7 @@ def to_code(config):
mqtt = Pvariable(config[CONF_ID], rhs)
if not config.get(CONF_DISCOVERY, True):
add(mqtt.disable_discovery())
if CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
elif CONF_DISCOVERY_RETAIN in config or CONF_DISCOVERY_PREFIX in config:
discovery_retain = config.get(CONF_DISCOVERY_RETAIN, True)
discovery_prefix = config.get(CONF_DISCOVERY_PREFIX, 'homeassistant')
add(mqtt.set_discovery_info(discovery_prefix, discovery_retain))

View File

@@ -1,10 +1,10 @@
import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml import core
import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_AP, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, CONF_DOMAIN, \
CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_REBOOT_TIMEOUT, \
CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266
CONF_GATEWAY, CONF_HOSTNAME, CONF_ID, CONF_MANUAL_IP, CONF_PASSWORD, CONF_POWER_SAVE_MODE,\
CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, CONF_SUBNET, ESP_PLATFORM_ESP8266
from esphomeyaml.helpers import App, Pvariable, StructInitializer, add, esphomelib_ns, global_ns
@@ -70,6 +70,12 @@ ManualIP = esphomelib_ns.ManualIP
WiFiComponent = esphomelib_ns.WiFiComponent
WiFiAp = esphomelib_ns.WiFiAp
WIFI_POWER_SAVE_MODES = {
'NONE': esphomelib_ns.WIFI_POWER_SAVE_NONE,
'LIGHT': esphomelib_ns.WIFI_POWER_SAVE_LIGHT,
'HIGH': esphomelib_ns.WIFI_POWER_SAVE_HIGH,
}
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(WiFiComponent),
vol.Optional(CONF_SSID): cv.ssid,
@@ -79,6 +85,7 @@ CONFIG_SCHEMA = vol.All(vol.Schema({
vol.Optional(CONF_HOSTNAME): cv.hostname,
vol.Optional(CONF_DOMAIN, default='.local'): cv.domainname,
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_POWER_SAVE_MODE): vol.All(vol.Upper, cv.one_of(*WIFI_POWER_SAVE_MODES)),
}), validate)
@@ -127,6 +134,9 @@ def to_code(config):
if CONF_REBOOT_TIMEOUT in config:
add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
if CONF_POWER_SAVE_MODE in config:
add(wifi.set_power_save_mode(WIFI_POWER_SAVE_MODES[CONF_POWER_SAVE_MODE]))
def lib_deps(config):
if core.ESP_PLATFORM == ESP_PLATFORM_ESP8266:

View File

@@ -1,6 +1,6 @@
{
"name": "esphomeyaml",
"version": "1.8.0",
"version": "1.8.2",
"slug": "esphomeyaml",
"description": "esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices.",
"url": "https://esphomelib.com/esphomeyaml/index.html",

View File

@@ -28,7 +28,7 @@ def get_component(domain):
path = 'esphomeyaml.components.{}'.format(domain)
try:
module = importlib.import_module(path)
except ImportError as err:
except (ImportError, ValueError) as err:
_LOGGER.debug(err)
else:
_COMPONENT_CACHE[domain] = module
@@ -183,7 +183,7 @@ def validate_config(config):
p_domain = u'{}.{}'.format(domain, p_name)
platform = get_platform(domain, p_name)
if platform is None:
result.add_error(u"Platform not found: {}".format(p_domain), p_domain, p_config)
result.add_error(u"Platform not found: '{}'".format(p_domain), p_domain, p_config)
continue
success = True

View File

@@ -2,10 +2,10 @@
MAJOR_VERSION = 1
MINOR_VERSION = 8
PATCH_VERSION = '0'
PATCH_VERSION = '2'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
ESPHOMELIB_VERSION = '1.8.0'
ESPHOMELIB_VERSION = '1.8.2'
ESP_PLATFORM_ESP32 = 'ESP32'
ESP_PLATFORM_ESP8266 = 'ESP8266'
@@ -338,6 +338,7 @@ CONF_DAYS_OF_MONTH = 'days_of_month'
CONF_MONTHS = 'months'
CONF_DAYS_OF_WEEK = 'days_of_week'
CONF_CRON = 'cron'
CONF_POWER_SAVE_MODE = 'power_save_mode'
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'

View File

@@ -242,3 +242,4 @@ CONFIG_PATH = None
ESP_PLATFORM = ''
BOARD = ''
RAW_CONFIG = None
NAME = ''

View File

@@ -1,5 +1,7 @@
import logging
import os
import re
import subprocess
import voluptuous as vol
@@ -15,6 +17,8 @@ from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import App, NoArg, Pvariable, add, const_char_p, esphomelib_ns, \
relative_path
_LOGGER = logging.getLogger(__name__)
LIBRARY_URI_REPO = u'https://github.com/OttoWinter/esphomelib.git'
BUILD_FLASH_MODES = ['qio', 'qout', 'dio', 'dout']
@@ -42,11 +46,20 @@ def validate_board(value):
def validate_simple_esphomelib_version(value):
value = cv.string_strict(value)
if value.upper() == 'LATEST':
return LIBRARY_URI_REPO + '#v{}'.format(ESPHOMELIB_VERSION)
return {
CONF_REPOSITORY: LIBRARY_URI_REPO,
CONF_TAG: 'v' + ESPHOMELIB_VERSION,
}
elif value.upper() == 'DEV':
return LIBRARY_URI_REPO
return {
CONF_REPOSITORY: LIBRARY_URI_REPO,
CONF_BRANCH: 'master'
}
elif VERSION_REGEX.match(value) is not None:
return LIBRARY_URI_REPO + '#v{}'.format(value)
return {
CONF_REPOSITORY: LIBRARY_URI_REPO,
CONF_TAG: 'v' + value,
}
return value
@@ -60,12 +73,11 @@ def validate_local_esphomelib_version(value):
return value
def convert_esphomelib_version_schema(value):
if CONF_COMMIT in value:
return value[CONF_REPOSITORY] + '#' + value[CONF_COMMIT]
if CONF_BRANCH in value:
return value[CONF_REPOSITORY] + '#' + value[CONF_BRANCH]
return value[CONF_REPOSITORY] + '#' + value[CONF_TAG]
def validate_commit(value):
value = cv.string(value)
if re.match(r"^[0-9a-f]{7,}$", value) is None:
raise vol.Invalid("Commit option only accepts commit hashes in hex format.")
return value
ESPHOMELIB_VERSION_SCHEMA = vol.Any(
@@ -76,12 +88,11 @@ ESPHOMELIB_VERSION_SCHEMA = vol.Any(
vol.All(
vol.Schema({
vol.Optional(CONF_REPOSITORY, default=LIBRARY_URI_REPO): cv.string,
vol.Optional(CONF_COMMIT, 'tag'): cv.string,
vol.Optional(CONF_BRANCH, 'tag'): cv.string,
vol.Optional(CONF_TAG, 'tag'): cv.string,
vol.Optional(CONF_COMMIT): validate_commit,
vol.Optional(CONF_BRANCH): cv.string,
vol.Optional(CONF_TAG): cv.string,
}),
cv.has_at_most_one_key(CONF_COMMIT, CONF_BRANCH, CONF_TAG),
convert_esphomelib_version_schema
cv.has_at_most_one_key(CONF_COMMIT, CONF_BRANCH, CONF_TAG)
),
)
@@ -108,8 +119,8 @@ PLATFORMIO_ESP8266_LUT = {
}
PLATFORMIO_ESP32_LUT = {
'1.0.0': 'espressif32@1.3.0',
'RECOMMENDED': 'espressif32@>=1.3.0',
'1.0.0': 'espressif32@1.4.0',
'RECOMMENDED': 'espressif32@>=1.4.0',
'LATEST': 'espressif32',
'DEV': ARDUINO_VERSION_ESP32_DEV,
}
@@ -138,6 +149,10 @@ def validate_arduino_version(value):
raise NotImplementedError
def default_build_path():
return core.NAME
CONFIG_SCHEMA = vol.Schema({
vol.Required(CONF_NAME): cv.valid_name,
vol.Required(CONF_PLATFORM): vol.All(vol.Upper, cv.one_of('ESP8266', 'ESPRESSIF8266',
@@ -146,7 +161,7 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_ESPHOMELIB_VERSION, default='latest'): ESPHOMELIB_VERSION_SCHEMA,
vol.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version,
vol.Optional(CONF_USE_CUSTOM_CODE, default=False): cv.boolean,
vol.Optional(CONF_BUILD_PATH): cv.string,
vol.Optional(CONF_BUILD_PATH, default=default_build_path): cv.string,
vol.Optional(CONF_BOARD_FLASH_MODE): vol.All(vol.Lower, cv.one_of(*BUILD_FLASH_MODES)),
vol.Optional(CONF_ON_BOOT): vol.All(cv.ensure_list, [automation.validate_automation({
@@ -173,14 +188,52 @@ def preload_core_config(config):
raise ESPHomeYAMLError("esphomeyaml.platform not specified.")
if CONF_BOARD not in core_conf:
raise ESPHomeYAMLError("esphomeyaml.board not specified.")
if CONF_NAME not in core_conf:
raise ESPHomeYAMLError("esphomeyaml.name not specified.")
try:
core.ESP_PLATFORM = validate_platform(core_conf[CONF_PLATFORM])
core.BOARD = validate_board(core_conf[CONF_BOARD])
core.NAME = cv.valid_name(core_conf[CONF_NAME])
except vol.Invalid as e:
raise ESPHomeYAMLError(unicode(e))
def run_command(*args):
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
rc = p.returncode
return rc, stdout, stderr
def update_esphomelib_repo(config):
esphomelib_version = config[CONF_ESPHOMELIB_VERSION]
if CONF_REPOSITORY not in esphomelib_version:
return
build_path = relative_path(config[CONF_BUILD_PATH])
esphomelib_path = os.path.join(build_path, '.piolibdeps', 'esphomelib')
is_default_branch = all(x not in esphomelib_version
for x in (CONF_BRANCH, CONF_TAG, CONF_COMMIT))
if not (CONF_BRANCH in esphomelib_version or is_default_branch):
# Git commit hash or tag cannot be updated
return
rc, _, _ = run_command('git', '-C', esphomelib_path, '--help')
if rc != 0:
# git not installed or repo not downloaded yet
return
rc, _, _ = run_command('git', '-C', esphomelib_path, 'diff-index', '--quiet', 'HEAD', '--')
if rc != 0:
# local changes, cannot update
_LOGGER.warn("Local changes in esphomelib copy from git. Will not auto-update.")
return
rc, _, _ = run_command('git', '-C', esphomelib_path, 'pull')
if rc != 0:
_LOGGER.warn("Couldn't auto-update local git copy of esphomelib.")
return
def to_code(config):
add(App.set_name(config[CONF_NAME]))
@@ -197,3 +250,5 @@ def to_code(config):
rhs = App.register_component(LoopTrigger.new())
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
update_esphomelib_repo(config)

View File

@@ -9,10 +9,11 @@ import os
import random
import subprocess
from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_BUILD_PATH
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml import const, core, __main__
from esphomeyaml.__main__ import get_serial_ports, get_base_path, get_name
from esphomeyaml.helpers import quote
from esphomeyaml.__main__ import get_serial_ports
from esphomeyaml.helpers import quote, relative_path
try:
import tornado
@@ -116,6 +117,13 @@ class EsphomeyamlValidateHandler(EsphomeyamlCommandWebSocket):
return ["esphomeyaml", config_file, "config"]
class EsphomeyamlCleanMqttHandler(EsphomeyamlCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphomeyaml", config_file, "clean-mqtt"]
class SerialPortRequestHandler(BaseHandler):
def get(self):
if not self.is_authenticated():
@@ -161,10 +169,10 @@ class DownloadBinaryRequestHandler(BaseHandler):
config_file = os.path.join(CONFIG_DIR, configuration)
core.CONFIG_PATH = config_file
config = __main__.read_config(core.CONFIG_PATH)
name = get_name(config)
path = os.path.join(get_base_path(config), '.pioenvs', name, 'firmware.bin')
build_path = relative_path(config[CONF_ESPHOMEYAML][CONF_BUILD_PATH])
path = os.path.join(build_path, '.pioenvs', core.NAME, 'firmware.bin')
self.set_header('Content-Type', 'application/octet-stream')
self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(name))
self.set_header("Content-Disposition", 'attachment; filename="{}.bin"'.format(core.NAME))
with open(path, 'rb') as f:
while 1:
data = f.read(16384) # or some other nice-sized chunk
@@ -212,6 +220,7 @@ def make_app(debug=False):
(r"/run", EsphomeyamlRunHandler),
(r"/compile", EsphomeyamlCompileHandler),
(r"/validate", EsphomeyamlValidateHandler),
(r"/clean-mqtt", EsphomeyamlCleanMqttHandler),
(r"/download.bin", DownloadBinaryRequestHandler),
(r"/serial-ports", SerialPortRequestHandler),
(r"/wizard.html", WizardRequestHandler),
@@ -250,6 +259,12 @@ def start_web_server(args):
args.port, CONFIG_DIR)
app = make_app(args.verbose)
app.listen(args.port)
if args.open_ui:
import webbrowser
webbrowser.open('localhost:{}'.format(args.port))
try:
tornado.ioloop.IOLoop.current().start()
except KeyboardInterrupt:

View File

@@ -159,6 +159,10 @@
margin-right: 24px;
width: 350px;
}
.dropdown-trigger {
cursor: pointer;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
@@ -191,7 +195,7 @@
<main>
<div class="container">
{% for file, full_path in zip(files, full_path_files) %}
{% for i, (file, full_path) in enumerate(zip(files, full_path_files)) %}
<div class="row">
<div class="col s8 offset-s2 m10 offset-m1 l12">
<div class="card horizontal">
@@ -200,7 +204,10 @@
</div>
<div class="card-stacked">
<div class="card-content">
<span class="card-title">{{ escape(file) }}</span>
<span class="card-title">
{{ escape(file) }}
<i class="material-icons right dropdown-trigger" data-target="dropdown-{{ i }}">more_vert</i>
</span>
<p>
Full path: <code class="inlinecode">{{ escape(full_path) }}</code>
</p>
@@ -211,6 +218,9 @@
<a href="#" class="action-show-logs" data-node="{{ file }}">Show Logs</a>
<a href="#" class="action-validate" data-node="{{ file }}">Validate</a>
</div>
<ul id="dropdown-{{ i }}" class="dropdown-content">
<li><a href="#" class="action-clean-mqtt" data-node="{{ file }}">Clean MQTT</a></li>
</ul>
</div>
</div>
</div>
@@ -462,6 +472,18 @@
</div>
</div>
<div id="modal-clean-mqtt" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Clean MQTT discovery <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<a class="btn-floating btn-large ribbon-fab waves-effect waves-light pink accent-2" id="setup-wizard-start">
<i class="material-icons">add</i>
</a>
@@ -539,6 +561,7 @@
if (allEqual)
return;
}
const hasNewPort = response.length >= ports.length;
ports = response;
@@ -559,7 +582,7 @@
}
M.FormSelect.init(portSelect, {});
if (!begin)
if (!begin && hasNewPort)
M.toast({html: "Discovered new serial port."});
});
};
@@ -784,6 +807,48 @@
link.click();
});
const cleanMqttModalElem = document.getElementById("modal-clean-mqtt");
document.querySelectorAll(".action-clean-mqtt").forEach((btn) => {
btn.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(cleanMqttModalElem);
const log = cleanMqttModalElem.querySelector(".log");
log.innerHTML = "";
const stopLogsButton = cleanMqttModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = cleanMqttModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/clean-mqtt");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
const msg = data.data;
log.innerHTML += colorReplace(msg);
} else if (data.event === "exit") {
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const modalSetupElem = document.getElementById("modal-wizard");
const setupWizardStart = document.getElementById('setup-wizard-start');
const startWizard = () => {

View File

@@ -106,7 +106,7 @@ class ExpressionList(Expression):
self.args.append(exp)
def __str__(self):
text = u", ".join(str(x) for x in self.args)
text = u", ".join(unicode(x) for x in self.args)
return indent_all_but_first_and_last(text)

View File

@@ -83,7 +83,9 @@ def clear_topic(config, topic, username=None, password=None, client_id=None):
discovery_prefix = config[CONF_MQTT].get(CONF_DISCOVERY_PREFIX, u'homeassistant')
name = config[CONF_ESPHOMEYAML][CONF_NAME]
topic = u'{}/+/{}/#'.format(discovery_prefix, name)
_LOGGER.info(u"Clearing messages from %s", topic)
_LOGGER.info(u"Clearing messages from '%s'", topic)
_LOGGER.info(u"Please close this window when no more messages appear and the "
u"MQTT topic has been cleared of retained messages.")
def on_message(client, userdata, msg):
if not msg.payload or not msg.retain:

View File

@@ -7,9 +7,9 @@ import os
from esphomeyaml import core
from esphomeyaml.config import iter_components
from esphomeyaml.const import CONF_ARDUINO_VERSION, CONF_BOARD, CONF_BOARD_FLASH_MODE, \
CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, CONF_LOCAL, CONF_NAME, CONF_USE_CUSTOM_CODE, \
ESP_PLATFORM_ESP32, ARDUINO_VERSION_ESP32_DEV
from esphomeyaml.const import ARDUINO_VERSION_ESP32_DEV, CONF_ARDUINO_VERSION, CONF_BOARD, \
CONF_BOARD_FLASH_MODE, CONF_ESPHOMELIB_VERSION, CONF_ESPHOMEYAML, CONF_LOCAL, CONF_NAME, \
CONF_USE_CUSTOM_CODE, ESP_PLATFORM_ESP32, CONF_REPOSITORY, CONF_COMMIT, CONF_BRANCH, CONF_TAG
from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.core_config import VERSION_REGEX
from esphomeyaml.helpers import relative_path
@@ -60,8 +60,13 @@ lib_deps =
build_flags =
{build_flags}
${{common.build_flags}}
upload_speed = {upload_speed}
"""
UPLOAD_SPEED_OVERRIDE = {
'esp210': 57600,
}
def get_build_flags(config, key):
build_flags = set()
@@ -86,6 +91,7 @@ def get_ini_content(config, path):
u'platform': config[CONF_ESPHOMEYAML][CONF_ARDUINO_VERSION],
u'board': config[CONF_ESPHOMEYAML][CONF_BOARD],
u'build_flags': u'',
u'upload_speed': UPLOAD_SPEED_OVERRIDE.get(core.BOARD, 115200),
}
build_flags = set()
if not config[CONF_ESPHOMEYAML][CONF_USE_CUSTOM_CODE]:
@@ -105,8 +111,13 @@ def get_ini_content(config, path):
lib_version = config[CONF_ESPHOMEYAML][CONF_ESPHOMELIB_VERSION]
lib_path = os.path.join(path, 'lib')
dst_path = os.path.join(lib_path, 'esphomelib')
if isinstance(lib_version, (str, unicode)):
lib_deps.add(lib_version)
if CONF_REPOSITORY in lib_version:
tag = next((lib_version[x] for x in (CONF_COMMIT, CONF_BRANCH, CONF_TAG)
if x in lib_version), None)
if tag is None:
lib_deps.add(lib_version[CONF_REPOSITORY])
else:
lib_deps.add(lib_version[CONF_REPOSITORY] + '#' + tag)
if os.path.islink(dst_path):
os.unlink(dst_path)
else:

View File

@@ -1,7 +1,7 @@
voluptuous==0.11.1
platformio==3.5.2
pyyaml==3.12
paho-mqtt==1.3.1
colorlog==3.1.2
tornado==5.0.2
esptool==2.3.1
voluptuous>=0.11.1
platformio>=3.5.3
pyyaml>=3.12
paho-mqtt>=1.3.1
colorlog>=3.1.2
tornado>=5.0.0
esptool>=2.3.1

View File

@@ -23,7 +23,7 @@ DOWNLOAD_URL = '{}/archive/{}.zip'.format(GITHUB_URL, const.__version__)
REQUIRES = [
'voluptuous>=0.11.1',
'platformio>=3.5.2',
'platformio>=3.5.3',
'pyyaml>=3.12',
'paho-mqtt>=1.3.1',
'colorlog>=3.1.2',

View File

@@ -21,7 +21,7 @@ esphomeyaml:
then:
- lambda: >-
ESP_LOGV("main", "ON LOOP!");
build_path: build
build_path: build/test1
wifi:
ssid: 'MySSID'
@@ -194,9 +194,6 @@ sensor:
retain: False
availability:
state_topic: livingroom/custom_state_topic
- platform: ble_rssi
mac_address: AC:37:43:77:5F:4C
name: "BLE Google Home Mini RSSI value"
- platform: bme280
temperature:
name: "Outside Temperature"
@@ -427,26 +424,6 @@ sensor:
- platform: wifi_signal
name: "WiFi Signal Sensor"
update_interval: 15s
- platform: xiaomi_miflora
mac_address: 94:2B:FF:5C:91:61
temperature:
name: "Xiaomi MiFlora Temperature"
moisture:
name: "Xiaomi MiFlora Moisture"
illuminance:
name: "Xiaomi MiFlora Illuminance"
conductivity:
name: "Xiaomi MiFlora Soil Conductivity"
battery_level:
name: "Xiaomi MiFlora Battery Level"
- platform: xiaomi_mijia
mac_address: 7A:80:8E:19:36:BA
temperature:
name: "Xiaomi MiJia Temperature"
humidity:
name: "Xiaomi MiJia Humidity"
battery_level:
name: "Xiaomi MiJia Battery Level"
esp32_touch:
@@ -467,6 +444,7 @@ binary_sensor:
- invert:
- delayed_on: 40ms
- delayed_off: 40ms
- heartbeat: 1s
on_press:
then:
- lambda: >-
@@ -496,9 +474,6 @@ binary_sensor:
id: binary_sensor1
- platform: status
name: "Living Room Status"
- platform: esp32_ble_tracker
mac_address: AC:37:43:77:5F:4C
name: "ESP32 BLE Tracker Google Home Mini"
- platform: esp32_touch
name: "ESP32 Touch Pad GPIO27"
pin: GPIO27
@@ -888,13 +863,6 @@ remote_receiver:
pin: GPIO32
dump: all
esp32_ble_tracker:
scan_interval: 300s
esp32_ble_beacon:
type: iBeacon
uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98'
status_led:
pin: GPIO2

102
tests/test2.yaml Normal file
View File

@@ -0,0 +1,102 @@
esphomeyaml:
name: test1
platform: ESP32
board: nodemcu-32s
# Use latest upstream esphomelib git version.
esphomelib_version: dev
# Use this for testing while developing:
# esphomelib_version:
# local: ~/path/to/esphomelib
use_custom_code: true
build_path: build/test2
wifi:
ssid: 'MySSID'
password: 'password1'
reboot_timeout: 120s
mqtt:
broker: '192.168.178.84'
port: 1883
username: 'debug'
password: 'debug'
i2c:
sda: 21
scl: 22
scan: False
spi:
clk_pin: GPIO21
mosi_pin: GPIO22
miso_pin: GPIO23
uart:
tx_pin: GPIO22
rx_pin: GPIO23
baud_rate: 115200
ota:
safe_mode: True
port: 3286
logger:
level: DEBUG
web_server:
deep_sleep:
run_duration: 20s
sleep_duration: 50s
sensor:
- platform: ble_rssi
mac_address: AC:37:43:77:5F:4C
name: "BLE Google Home Mini RSSI value"
- platform: xiaomi_miflora
mac_address: 94:2B:FF:5C:91:61
temperature:
name: "Xiaomi MiFlora Temperature"
moisture:
name: "Xiaomi MiFlora Moisture"
illuminance:
name: "Xiaomi MiFlora Illuminance"
conductivity:
name: "Xiaomi MiFlora Soil Conductivity"
battery_level:
name: "Xiaomi MiFlora Battery Level"
- platform: xiaomi_mijia
mac_address: 7A:80:8E:19:36:BA
temperature:
name: "Xiaomi MiJia Temperature"
humidity:
name: "Xiaomi MiJia Humidity"
battery_level:
name: "Xiaomi MiJia Battery Level"
esp32_touch:
setup_mode: True
binary_sensor:
- platform: esp32_ble_tracker
mac_address: AC:37:43:77:5F:4C
name: "ESP32 BLE Tracker Google Home Mini"
- platform: esp32_touch
name: "ESP32 Touch Pad GPIO27"
pin: GPIO27
threshold: 1000
remote_receiver:
pin: GPIO32
dump: []
esp32_ble_tracker:
scan_interval: 300s
esp32_ble_beacon:
type: iBeacon
uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98'
status_led:
pin: GPIO2