Add MQTT publish JSON action and subscribe JSON trigger (#193)

* Add MQTT publish JSON action and subscribe JSON trigger

* Lint
This commit is contained in:
Otto Winter 2018-10-20 12:41:00 +02:00 committed by GitHub
parent 81bc400340
commit 629f2b128e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 233 additions and 140 deletions

View file

@ -16,6 +16,7 @@ from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, \ from esphomeyaml.helpers import AssignmentExpression, Expression, RawStatement, \
_EXPRESSIONS, add, \ _EXPRESSIONS, add, \
add_job, color, flush_tasks, indent, quote, statement, relative_path add_job, color, flush_tasks, indent, quote, statement, relative_path
from esphomeyaml.util import safe_print
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -39,11 +40,11 @@ def choose_serial_port(config):
if not result: if not result:
return 'OTA' return 'OTA'
print(u"Found multiple serial port options, please choose one:") safe_print(u"Found multiple serial port options, please choose one:")
for i, (res, desc) in enumerate(result): for i, (res, desc) in enumerate(result):
print(u" [{}] {} ({})".format(i, res, desc)) safe_print(u" [{}] {} ({})".format(i, res, desc))
print(u" [{}] Over The Air ({})".format(len(result), get_upload_host(config))) safe_print(u" [{}] Over The Air ({})".format(len(result), get_upload_host(config)))
print() safe_print()
while True: while True:
opt = raw_input('(number): ') opt = raw_input('(number): ')
if opt in result: if opt in result:
@ -55,7 +56,7 @@ def choose_serial_port(config):
raise ValueError raise ValueError
break break
except ValueError: except ValueError:
print(color('red', u"Invalid option: '{}'".format(opt))) safe_print(color('red', u"Invalid option: '{}'".format(opt)))
if opt == len(result): if opt == len(result):
return 'OTA' return 'OTA'
return result[opt][0] return result[opt][0]
@ -111,10 +112,7 @@ def run_miniterm(config, port, escape=False):
message = time + line message = time + line
if escape: if escape:
message = message.replace('\033', '\\033') message = message.replace('\033', '\\033')
try: safe_print(message)
print(message)
except UnicodeEncodeError:
print(message.encode('ascii', 'backslashreplace'))
def write_cpp(config): def write_cpp(config):
@ -295,7 +293,7 @@ def strip_default_ids(config):
def command_config(args, config): def command_config(args, config):
if not args.verbose: if not args.verbose:
config = strip_default_ids(config) config = strip_default_ids(config)
print(yaml_util.dump(config)) safe_print(yaml_util.dump(config))
return 0 return 0
@ -354,7 +352,7 @@ def command_mqtt_fingerprint(args, config):
def command_version(args): def command_version(args):
print(u"Version: {}".format(const.__version__)) safe_print(u"Version: {}".format(const.__version__))
return 0 return 0
@ -496,7 +494,7 @@ def run_esphomeyaml(argv):
except ESPHomeYAMLError as e: except ESPHomeYAMLError as e:
_LOGGER.error(e) _LOGGER.error(e)
return 1 return 1
print(u"Unknown command {}".format(args.command)) safe_print(u"Unknown command {}".format(args.command))
return 1 return 1

View file

@ -10,10 +10,10 @@ from esphomeyaml.const import CONF_BIRTH_MESSAGE, CONF_BROKER, CONF_CLIENT_ID, C
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LEVEL, \ CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_RETAIN, CONF_ID, CONF_KEEPALIVE, CONF_LEVEL, \
CONF_LOG_TOPIC, CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, \ CONF_LOG_TOPIC, CONF_ON_MESSAGE, CONF_PASSWORD, CONF_PAYLOAD, CONF_PORT, CONF_QOS, \
CONF_REBOOT_TIMEOUT, CONF_RETAIN, CONF_SHUTDOWN_MESSAGE, CONF_SSL_FINGERPRINTS, CONF_TOPIC, \ CONF_REBOOT_TIMEOUT, CONF_RETAIN, CONF_SHUTDOWN_MESSAGE, CONF_SSL_FINGERPRINTS, CONF_TOPIC, \
CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, CONF_WILL_MESSAGE CONF_TOPIC_PREFIX, CONF_TRIGGER_ID, CONF_USERNAME, CONF_WILL_MESSAGE, CONF_ON_JSON_MESSAGE
from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression, \ from esphomeyaml.helpers import App, ArrayInitializer, Pvariable, RawExpression, \
StructInitializer, TemplateArguments, add, esphomelib_ns, optional, std_string, templatable, \ StructInitializer, TemplateArguments, add, esphomelib_ns, optional, std_string, templatable, \
uint8, bool_ uint8, bool_, JsonObjectRef, process_lambda, JsonObjectConstRef
def validate_message_just_topic(value): def validate_message_just_topic(value):
@ -37,7 +37,9 @@ mqtt_ns = esphomelib_ns.namespace('mqtt')
MQTTMessage = mqtt_ns.MQTTMessage MQTTMessage = mqtt_ns.MQTTMessage
MQTTClientComponent = mqtt_ns.MQTTClientComponent MQTTClientComponent = mqtt_ns.MQTTClientComponent
MQTTPublishAction = mqtt_ns.MQTTPublishAction MQTTPublishAction = mqtt_ns.MQTTPublishAction
MQTTPublishJsonAction = mqtt_ns.MQTTPublishJsonAction
MQTTMessageTrigger = mqtt_ns.MQTTMessageTrigger MQTTMessageTrigger = mqtt_ns.MQTTMessageTrigger
MQTTJsonMessageTrigger = mqtt_ns.MQTTJsonMessageTrigger
def validate_broker(value): def validate_broker(value):
@ -79,9 +81,14 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds, vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.validate_automation({ vol.Optional(CONF_ON_MESSAGE): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTMessageTrigger),
vol.Required(CONF_TOPIC): cv.publish_topic, vol.Required(CONF_TOPIC): cv.subscribe_topic,
vol.Optional(CONF_QOS, default=0): cv.mqtt_qos, vol.Optional(CONF_QOS, default=0): cv.mqtt_qos,
})]) })]),
vol.Optional(CONF_ON_JSON_MESSAGE): vol.All(cv.ensure_list, [automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(MQTTJsonMessageTrigger),
vol.Required(CONF_TOPIC): cv.subscribe_topic,
vol.Optional(CONF_QOS, default=0): cv.mqtt_qos,
})]),
}) })
@ -160,6 +167,11 @@ def to_code(config):
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs) trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, std_string, conf) automation.build_automation(trigger, std_string, conf)
for conf in config.get(CONF_ON_JSON_MESSAGE, []):
rhs = mqtt.make_json_message_trigger(conf[CONF_TOPIC], conf[CONF_QOS])
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, JsonObjectConstRef, conf)
CONF_MQTT_PUBLISH = 'mqtt.publish' CONF_MQTT_PUBLISH = 'mqtt.publish'
MQTT_PUBLISH_ACTION_SCHEMA = vol.Schema({ MQTT_PUBLISH_ACTION_SCHEMA = vol.Schema({
@ -194,6 +206,35 @@ def mqtt_publish_action_to_code(config, action_id, arg_type):
yield action yield action
CONF_MQTT_PUBLISH_JSON = 'mqtt.publish_json'
MQTT_PUBLISH_JSON_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_TOPIC): cv.templatable(cv.publish_topic),
vol.Required(CONF_PAYLOAD): cv.lambda_,
vol.Optional(CONF_QOS): cv.mqtt_qos,
vol.Optional(CONF_RETAIN): cv.boolean,
})
@ACTION_REGISTRY.register(CONF_MQTT_PUBLISH_JSON, MQTT_PUBLISH_JSON_ACTION_SCHEMA)
def mqtt_publish_json_action_to_code(config, action_id, arg_type):
template_arg = TemplateArguments(arg_type)
rhs = App.Pget_mqtt_client().Pmake_publish_json_action(template_arg)
type = MQTTPublishJsonAction.template(template_arg)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_TOPIC], arg_type, std_string):
yield None
add(action.set_topic(template_))
for lambda_ in process_lambda(config[CONF_PAYLOAD], [(arg_type, 'x'), (JsonObjectRef, 'root')]):
yield None
add(action.set_payload(lambda_))
if CONF_QOS in config:
add(action.set_qos(config[CONF_QOS]))
if CONF_RETAIN in config:
add(action.set_retain(config[CONF_RETAIN]))
yield action
def required_build_flags(config): def required_build_flags(config):
if CONF_SSL_FINGERPRINTS in config: if CONF_SSL_FINGERPRINTS in config:
return '-DASYNC_TCP_SSL_ENABLED=1' return '-DASYNC_TCP_SSL_ENABLED=1'

View file

@ -11,6 +11,7 @@ from esphomeyaml import core, yaml_util, core_config
from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_PLATFORM, CONF_WIFI, ESP_PLATFORMS from esphomeyaml.const import CONF_ESPHOMEYAML, CONF_PLATFORM, CONF_WIFI, ESP_PLATFORMS
from esphomeyaml.core import ESPHomeYAMLError from esphomeyaml.core import ESPHomeYAMLError
from esphomeyaml.helpers import color from esphomeyaml.helpers import color
from esphomeyaml.util import safe_print
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -306,17 +307,17 @@ def dump_dict(layer, indent_count=3, listi=False, **kwargs):
if isinstance(layer, dict): if isinstance(layer, dict):
for key, value in sorted(layer.items(), key=sort_dict_key): for key, value in sorted(layer.items(), key=sort_dict_key):
if isinstance(value, (dict, list)): if isinstance(value, (dict, list)):
print(indent_str, key + ':', line_info(value, **kwargs)) safe_print(u"{} {}: {}".format(indent_str, key, line_info(value, **kwargs)))
dump_dict(value, indent_count + 2) dump_dict(value, indent_count + 2)
else: else:
print(indent_str, key + ':', value) safe_print(u"{} {}: {}".format(indent_str, key, value))
indent_str = indent_count * ' ' indent_str = indent_count * ' '
if isinstance(layer, (list, tuple)): if isinstance(layer, (list, tuple)):
for i in layer: for i in layer:
if isinstance(i, dict): if isinstance(i, dict):
dump_dict(i, indent_count + 2, True) dump_dict(i, indent_count + 2, True)
else: else:
print(' ', indent_str, i) safe_print(u" {} {}".format(indent_str, i))
def read_config(path): def read_config(path):
@ -334,10 +335,11 @@ def read_config(path):
excepts[domain].append(config) excepts[domain].append(config)
if excepts: if excepts:
print(color('bold_white', u"Failed config")) safe_print(color('bold_white', u"Failed config"))
for domain, config in excepts.iteritems(): for domain, config in excepts.iteritems():
print(' ', color('bold_red', domain + ':'), color('red', '', reset='red')) safe_print(u' {} {}'.format(color('bold_red', domain + u':'),
color('red', '', reset='red')))
dump_dict(config, reset='red') dump_dict(config, reset='red')
print(color('reset')) safe_print(color('reset'))
return None return None
return OrderedDict(res) return OrderedDict(res)

View file

@ -342,6 +342,7 @@ CONF_CRON = 'cron'
CONF_POWER_SAVE_MODE = 'power_save_mode' CONF_POWER_SAVE_MODE = 'power_save_mode'
CONF_POWER_ON_VALUE = 'power_on_value' CONF_POWER_ON_VALUE = 'power_on_value'
CONF_ON_TAG = 'on_tag' CONF_ON_TAG = 'on_tag'
CONF_ON_JSON_MESSAGE = 'on_json_message'
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_' ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage' ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'

View file

@ -536,6 +536,10 @@ class MockObj(Expression):
obj = MockObj(u'{} &'.format(self.base), u'') obj = MockObj(u'{} &'.format(self.base), u'')
obj.requires.append(self) obj.requires.append(self)
return obj return obj
if name == "const":
obj = MockObj(u'const {}'.format(self.base), u'')
obj.requires.append(self)
return obj
raise NotImplementedError() raise NotImplementedError()
def has_side_effects(self): def has_side_effects(self):
@ -568,6 +572,10 @@ NoArg = esphomelib_ns.NoArg
App = esphomelib_ns.App App = esphomelib_ns.App
Application = esphomelib_ns.namespace('Application') Application = esphomelib_ns.namespace('Application')
optional = esphomelib_ns.optional optional = esphomelib_ns.optional
arduino_json_ns = global_ns.namespace('ArduinoJson')
JsonObject = arduino_json_ns.JsonObject
JsonObjectRef = JsonObject.operator('ref')
JsonObjectConstRef = JsonObjectRef.operator('const')
GPIOPin = esphomelib_ns.GPIOPin GPIOPin = esphomelib_ns.GPIOPin
GPIOOutputPin = esphomelib_ns.GPIOOutputPin GPIOOutputPin = esphomelib_ns.GPIOOutputPin

View file

@ -14,6 +14,7 @@ from esphomeyaml.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOMEYA
CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \ CONF_MQTT, CONF_NAME, CONF_PASSWORD, CONF_PORT, CONF_TOPIC_PREFIX, \
CONF_USERNAME, CONF_TOPIC, CONF_SSL_FINGERPRINTS CONF_USERNAME, CONF_TOPIC, CONF_SSL_FINGERPRINTS
from esphomeyaml.helpers import color from esphomeyaml.helpers import color
from esphomeyaml.util import safe_print
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -70,10 +71,7 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None,
message = time + msg.payload message = time + msg.payload
if escape: if escape:
message = message.replace('\033', '\\033') message = message.replace('\033', '\\033')
try: safe_print(message)
print(message)
except UnicodeEncodeError:
print(message.encode('ascii', 'backslashreplace'))
return initialize(config, [topic], on_message, username, password, client_id) return initialize(config, [topic], on_message, username, password, client_id)
@ -113,6 +111,7 @@ def get_fingerprint(config):
sha1 = hashlib.sha1(cert_der).hexdigest() sha1 = hashlib.sha1(cert_der).hexdigest()
print(u"SHA1 Fingerprint: " + color('cyan', sha1)) safe_print(u"SHA1 Fingerprint: " + color('cyan', sha1))
print(u"Copy above string into mqtt.ssl_fingerprints section of {}".format(core.CONFIG_PATH)) safe_print(u"Copy the string above into mqtt.ssl_fingerprints section of {}"
u"".format(core.CONFIG_PATH))
return 0 return 0

View file

@ -1,3 +1,6 @@
from __future__ import print_function
class Registry(dict): class Registry(dict):
def register(self, name): def register(self, name):
def decorator(fun): def decorator(fun):
@ -14,3 +17,16 @@ class ServiceRegistry(dict):
return fun return fun
return decorator return decorator
def safe_print(message=""):
try:
print(message)
return
except UnicodeEncodeError:
pass
try:
print(message.encode('ascii', 'backslashreplace'))
except UnicodeEncodeError:
print("Cannot print line because of invalid locale!")

View file

@ -6,14 +6,13 @@ import unicodedata
import voluptuous as vol import voluptuous as vol
import esphomeyaml.config_validation as cv
from esphomeyaml.components import mqtt from esphomeyaml.components import mqtt
import esphomeyaml.config_validation as cv
from esphomeyaml.const import ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266 from esphomeyaml.const import ESP_PLATFORMS, ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266
from esphomeyaml.helpers import color from esphomeyaml.helpers import color
# pylint: disable=anomalous-backslash-in-string # pylint: disable=anomalous-backslash-in-string
from esphomeyaml.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS from esphomeyaml.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS
from esphomeyaml.util import safe_print
CORE_BIG = """ _____ ____ _____ ______ CORE_BIG = """ _____ ____ _____ ______
/ ____/ __ \| __ \| ____| / ____/ __ \| __ \| ____|
@ -52,7 +51,7 @@ OTA_BIG = """ ____ _______
""" """
# TODO handle escaping # TODO handle escaping
BASE_CONFIG = """esphomeyaml: BASE_CONFIG = u"""esphomeyaml:
name: {name} name: {name}
platform: {platform} platform: {platform}
board: {board} board: {board}
@ -76,9 +75,9 @@ def wizard_file(**kwargs):
config = BASE_CONFIG.format(**kwargs) config = BASE_CONFIG.format(**kwargs)
if kwargs['ota_password']: if kwargs['ota_password']:
config += "ota:\n password: '{}'\n".format(kwargs['ota_password']) config += u"ota:\n password: '{}'\n".format(kwargs['ota_password'])
else: else:
config += "ota:\n" config += u"ota:\n"
return config return config
@ -90,18 +89,18 @@ else:
from time import sleep from time import sleep
def print_step(step, big): def safe_print_step(step, big):
print() safe_print()
print() safe_print()
print("============= STEP {} =============".format(step)) safe_print("============= STEP {} =============".format(step))
print(big) safe_print(big)
print("===================================") safe_print("===================================")
sleep(0.25) sleep(0.25)
def default_input(text, default): def default_input(text, default):
print() safe_print()
print("Press ENTER for default ({})".format(default)) safe_print(u"Press ENTER for default ({})".format(default))
return raw_input(text.format(default)) or default return raw_input(text.format(default)) or default
@ -113,30 +112,30 @@ def strip_accents(string):
def wizard(path): def wizard(path):
if not path.endswith('.yaml') and not path.endswith('.yml'): if not path.endswith('.yaml') and not path.endswith('.yml'):
print("Please make your configuration file {} have the extension .yaml or .yml".format( safe_print(u"Please make your configuration file {} have the extension .yaml or .yml"
color('cyan', path))) u"".format(color('cyan', path)))
return 1 return 1
if os.path.exists(path): if os.path.exists(path):
print("Uh oh, it seems like {} already exists, please delete that file first " safe_print(u"Uh oh, it seems like {} already exists, please delete that file first "
"or chose another configuration file.".format(color('cyan', path))) u"or chose another configuration file.".format(color('cyan', path)))
return 1 return 1
print("Hi there!") safe_print("Hi there!")
sleep(1.5) sleep(1.5)
print("I'm the wizard of esphomeyaml :)") safe_print("I'm the wizard of esphomeyaml :)")
sleep(1.25) sleep(1.25)
print("And I'm here to help you get started with esphomeyaml.") safe_print("And I'm here to help you get started with esphomeyaml.")
sleep(2.0) sleep(2.0)
print("In 5 steps I'm going to guide you through creating a basic " safe_print("In 5 steps I'm going to guide you through creating a basic "
"configuration file for your custom ESP8266/ESP32 firmware. Yay!") "configuration file for your custom ESP8266/ESP32 firmware. Yay!")
sleep(3.0) sleep(3.0)
print() safe_print()
print_step(1, CORE_BIG) safe_print_step(1, CORE_BIG)
print("First up, please choose a " + color('green', 'name') + " for your node.") safe_print("First up, please choose a " + color('green', 'name') + " for your node.")
print("It should be a unique name that can be used to identify the device later.") safe_print("It should be a unique name that can be used to identify the device later.")
sleep(1) sleep(1)
print("For example, I like calling the node in my living room {}.".format( safe_print("For example, I like calling the node in my living room {}.".format(
color('bold_white', "livingroom"))) color('bold_white', "livingroom")))
print() safe_print()
sleep(1) sleep(1)
name = raw_input(color("bold_white", "(name): ")) name = raw_input(color("bold_white", "(name): "))
while True: while True:
@ -144,34 +143,34 @@ def wizard(path):
name = cv.valid_name(name) name = cv.valid_name(name)
break break
except vol.Invalid: except vol.Invalid:
print(color("red", "Oh noes, \"{}\" isn't a valid name. Names can only include " safe_print(color("red", u"Oh noes, \"{}\" isn't a valid name. Names can only include "
"numbers, letters and underscores.".format(name))) u"numbers, letters and underscores.".format(name)))
name = strip_accents(name).replace(' ', '_') name = strip_accents(name).replace(' ', '_')
name = u''.join(c for c in name if c in cv.ALLOWED_NAME_CHARS) name = u''.join(c for c in name if c in cv.ALLOWED_NAME_CHARS)
print("Shall I use \"{}\" as the name instead?".format(color('cyan', name))) safe_print(u"Shall I use \"{}\" as the name instead?".format(color('cyan', name)))
sleep(0.5) sleep(0.5)
name = default_input("(name [{}]): ", name) name = default_input(u"(name [{}]): ", name)
print("Great! Your node is now called \"{}\".".format(color('cyan', name))) safe_print(u"Great! Your node is now called \"{}\".".format(color('cyan', name)))
sleep(1) sleep(1)
print_step(2, ESP_BIG) safe_print_step(2, ESP_BIG)
print("Now I'd like to know what microcontroller you're using so that I can compile " safe_print("Now I'd like to know what microcontroller you're using so that I can compile "
"firmwares for it.") "firmwares for it.")
print("Are you using an " + color('green', 'ESP32') + " or " + safe_print("Are you using an " + color('green', 'ESP32') + " or " +
color('green', 'ESP8266') + " platform? (Choose ESP8266 for Sonoff devices)") color('green', 'ESP8266') + " platform? (Choose ESP8266 for Sonoff devices)")
while True: while True:
sleep(0.5) sleep(0.5)
print() safe_print()
print("Please enter either ESP32 or ESP8266.") safe_print("Please enter either ESP32 or ESP8266.")
platform = raw_input(color("bold_white", "(ESP32/ESP8266): ")) platform = raw_input(color("bold_white", "(ESP32/ESP8266): "))
try: try:
platform = vol.All(vol.Upper, vol.Any(*ESP_PLATFORMS))(platform) platform = vol.All(vol.Upper, vol.Any(*ESP_PLATFORMS))(platform)
break break
except vol.Invalid: except vol.Invalid:
print("Unfortunately, I can't find an espressif microcontroller called " safe_print(u"Unfortunately, I can't find an espressif microcontroller called "
"\"{}\". Please try again.".format(platform)) u"\"{}\". Please try again.".format(platform))
print("Thanks! You've chosen {} as your platform.".format(color('cyan', platform))) safe_print(u"Thanks! You've chosen {} as your platform.".format(color('cyan', platform)))
print() safe_print()
sleep(1) sleep(1)
if platform == ESP_PLATFORM_ESP32: if platform == ESP_PLATFORM_ESP32:
@ -179,18 +178,18 @@ def wizard(path):
else: else:
board_link = 'http://docs.platformio.org/en/latest/platforms/espressif8266.html#boards' board_link = 'http://docs.platformio.org/en/latest/platforms/espressif8266.html#boards'
print("Next, I need to know what " + color('green', 'board') + " you're using.") safe_print("Next, I need to know what " + color('green', 'board') + " you're using.")
sleep(0.5) sleep(0.5)
print("Please go to {} and choose a board.".format(color('green', board_link))) safe_print("Please go to {} and choose a board.".format(color('green', board_link)))
if platform == ESP_PLATFORM_ESP8266: if platform == ESP_PLATFORM_ESP8266:
print("(Type " + color('green', 'esp01_1m') + " for Sonoff devices)") safe_print("(Type " + color('green', 'esp01_1m') + " for Sonoff devices)")
print() safe_print()
# Don't sleep because user needs to copy link # Don't sleep because user needs to copy link
if platform == ESP_PLATFORM_ESP32: if platform == ESP_PLATFORM_ESP32:
print("For example \"{}\".".format(color("bold_white", 'nodemcu-32s'))) safe_print("For example \"{}\".".format(color("bold_white", 'nodemcu-32s')))
boards = list(ESP32_BOARD_PINS.keys()) boards = list(ESP32_BOARD_PINS.keys())
else: else:
print("For example \"{}\".".format(color("bold_white", 'nodemcuv2'))) safe_print("For example \"{}\".".format(color("bold_white", 'nodemcuv2')))
boards = list(ESP8266_BOARD_PINS.keys()) boards = list(ESP8266_BOARD_PINS.keys())
while True: while True:
board = raw_input(color("bold_white", "(board): ")) board = raw_input(color("bold_white", "(board): "))
@ -198,71 +197,73 @@ def wizard(path):
board = vol.All(vol.Lower, vol.Any(*boards))(board) board = vol.All(vol.Lower, vol.Any(*boards))(board)
break break
except vol.Invalid: except vol.Invalid:
print(color('red', "Sorry, I don't think the board \"{}\" exists.")) safe_print(color('red', "Sorry, I don't think the board \"{}\" exists."))
print() safe_print()
sleep(0.25) sleep(0.25)
print("Possible options are {}".format(', '.join(boards))) safe_print("Possible options are {}".format(', '.join(boards)))
print() safe_print()
print("Way to go! You've chosen {} as your board.".format(color('cyan', board))) safe_print(u"Way to go! You've chosen {} as your board.".format(color('cyan', board)))
print() safe_print()
sleep(1) sleep(1)
print_step(3, WIFI_BIG) safe_print_step(3, WIFI_BIG)
print("In this step, I'm going to create the configuration for " safe_print("In this step, I'm going to create the configuration for "
"WiFi.") "WiFi.")
print() safe_print()
sleep(1) sleep(1)
print("First, what's the " + color('green', 'SSID') + " (the name) of the WiFi network {} " safe_print("First, what's the " + color('green', 'SSID') +
"I should connect to?".format(name)) u" (the name) of the WiFi network {} I should connect to?".format(name))
sleep(1.5) sleep(1.5)
print("For example \"{}\".".format(color('bold_white', "Abraham Linksys"))) safe_print("For example \"{}\".".format(color('bold_white', "Abraham Linksys")))
while True: while True:
ssid = raw_input(color('bold_white', "(ssid): ")) ssid = raw_input(color('bold_white', "(ssid): "))
try: try:
ssid = cv.ssid(ssid) ssid = cv.ssid(ssid)
break break
except vol.Invalid: except vol.Invalid:
print(color('red', "Unfortunately, \"{}\" doesn't seem to be a valid SSID. " safe_print(color('red', u"Unfortunately, \"{}\" doesn't seem to be a valid SSID. "
"Please try again.".format(ssid))) u"Please try again.".format(ssid)))
print() safe_print()
sleep(1) sleep(1)
print("Thank you very much! You've just chosen \"{}\" as your SSID.".format( safe_print(u"Thank you very much! You've just chosen \"{}\" as your SSID."
color('cyan', ssid))) u"".format(color('cyan', ssid)))
print() safe_print()
sleep(0.75) sleep(0.75)
print("Now please state the " + color('green', 'password') + safe_print("Now please state the " + color('green', 'password') +
" of the WiFi network so that I can connect to it (Leave empty for no password)") " of the WiFi network so that I can connect to it (Leave empty for no password)")
print() safe_print()
print("For example \"{}\"".format(color('bold_white', 'PASSWORD42'))) safe_print("For example \"{}\"".format(color('bold_white', 'PASSWORD42')))
sleep(0.5) sleep(0.5)
psk = raw_input(color('bold_white', '(PSK): ')) psk = raw_input(color('bold_white', '(PSK): '))
print("Perfect! WiFi is now set up (you can create static IPs and so on later).") safe_print("Perfect! WiFi is now set up (you can create static IPs and so on later).")
sleep(1.5) sleep(1.5)
print_step(4, MQTT_BIG) safe_print_step(4, MQTT_BIG)
print("Almost there! Now let's setup MQTT so that your node can connect to the outside world.") safe_print("Almost there! Now let's setup MQTT so that your node can connect to the "
print() "outside world.")
safe_print()
sleep(1) sleep(1)
print("Please enter the " + color('green', 'address') + " of your MQTT broker.") safe_print("Please enter the " + color('green', 'address') + " of your MQTT broker.")
print() safe_print()
print("For example \"{}\".".format(color('bold_white', '192.168.178.84'))) safe_print("For example \"{}\".".format(color('bold_white', '192.168.178.84')))
while True: while True:
broker = raw_input(color('bold_white', "(broker): ")) broker = raw_input(color('bold_white', "(broker): "))
try: try:
broker = mqtt.validate_broker(broker) broker = mqtt.validate_broker(broker)
break break
except vol.Invalid as err: except vol.Invalid as err:
print(color('red', "The broker address \"{}\" seems to be invalid: {} :(".format( safe_print(color('red', u"The broker address \"{}\" seems to be invalid: {} :("
broker, err))) u"".format(broker, err)))
print("Please try again.") safe_print("Please try again.")
print() safe_print()
sleep(1) sleep(1)
print("Thanks! Now enter the " + color('green', 'username') + " and " + safe_print("Thanks! Now enter the " + color('green', 'username') + " and " +
color('green', 'password') + " for the MQTT broker. Leave empty for no authentication.") color('green', 'password') +
" for the MQTT broker. Leave empty for no authentication.")
mqtt_username = raw_input(color('bold_white', '(username): ')) mqtt_username = raw_input(color('bold_white', '(username): '))
mqtt_password = '' mqtt_password = ''
if mqtt_username: if mqtt_username:
@ -271,19 +272,19 @@ def wizard(path):
show = '*' * len(mqtt_password) show = '*' * len(mqtt_password)
if len(mqtt_password) >= 2: if len(mqtt_password) >= 2:
show = mqtt_password[:2] + '*' * len(mqtt_password) show = mqtt_password[:2] + '*' * len(mqtt_password)
print("MQTT Username: \"{}\"; Password: \"{}\"".format( safe_print(u"MQTT Username: \"{}\"; Password: \"{}\""
color('cyan', mqtt_username), color('cyan', show))) u"".format(color('cyan', mqtt_username), color('cyan', show)))
else: else:
print("No authentication for MQTT") safe_print("No authentication for MQTT")
print_step(5, OTA_BIG) safe_print_step(5, OTA_BIG)
print("Last step! esphomeyaml can automatically upload custom firmwares over WiFi " safe_print("Last step! esphomeyaml can automatically upload custom firmwares over WiFi "
"(over the air).") "(over the air).")
print("This can be insecure if you do not trust the WiFi network. Do you want to set " safe_print("This can be insecure if you do not trust the WiFi network. Do you want to set "
"an " + color('green', 'OTA password') + " for remote updates?") "an " + color('green', 'OTA password') + " for remote updates?")
print() safe_print()
sleep(0.25) sleep(0.25)
print("Press ENTER for no password") safe_print("Press ENTER for no password")
ota_password = raw_input(color('bold_white', '(password): ')) ota_password = raw_input(color('bold_white', '(password): '))
config = wizard_file(name=name, platform=platform, board=board, config = wizard_file(name=name, platform=platform, board=board,
@ -294,19 +295,19 @@ def wizard(path):
with codecs.open(path, 'w') as f_handle: with codecs.open(path, 'w') as f_handle:
f_handle.write(config) f_handle.write(config)
print() safe_print()
print(color('cyan', "DONE! I've now written a new configuration file to ") + safe_print(color('cyan', "DONE! I've now written a new configuration file to ") +
color('bold_cyan', path)) color('bold_cyan', path))
print() safe_print()
print("Next steps:") safe_print("Next steps:")
print(" > If you haven't already, enable MQTT discovery in Home Assistant:") safe_print(" > If you haven't already, enable MQTT discovery in Home Assistant:")
print() safe_print()
print(color('bold_white', "# In your configuration.yaml")) safe_print(color('bold_white', "# In your configuration.yaml"))
print(color('bold_white', "mqtt:")) safe_print(color('bold_white', "mqtt:"))
print(color('bold_white', " broker: {}".format(broker))) safe_print(color('bold_white', u" broker: {}".format(broker)))
print(color('bold_white', " # ...")) safe_print(color('bold_white', " # ..."))
print(color('bold_white', " discovery: True")) safe_print(color('bold_white', " discovery: True"))
print() safe_print()
print(" > Then follow the rest of the getting started guide:") safe_print(" > Then follow the rest of the getting started guide:")
print(" > https://esphomelib.com/esphomeyaml/guides/getting_started_command_line.html") safe_print(" > https://esphomelib.com/esphomeyaml/guides/getting_started_command_line.html")
return 0 return 0

View file

@ -102,6 +102,7 @@ def get_ini_content(config, path):
build_flags |= get_build_flags(config, 'build_flags') build_flags |= get_build_flags(config, 'build_flags')
build_flags |= get_build_flags(config, 'BUILD_FLAGS') build_flags |= get_build_flags(config, 'BUILD_FLAGS')
build_flags.add(u"-DESPHOMEYAML_USE") build_flags.add(u"-DESPHOMEYAML_USE")
build_flags.add("-Wno-unused-variable")
build_flags |= get_build_flags(config, 'required_build_flags') build_flags |= get_build_flags(config, 'required_build_flags')
build_flags |= get_build_flags(config, 'REQUIRED_BUILD_FLAGS') build_flags |= get_build_flags(config, 'REQUIRED_BUILD_FLAGS')

View file

@ -73,6 +73,24 @@ mqtt:
then: then:
- deep_sleep.enter: - deep_sleep.enter:
id: deep_sleep_1 id: deep_sleep_1
on_json_message:
topic: the/topic
then:
- lambda: |-
int data = x["my_data"];
ESP_LOGD("main", "The data is: %d", data);
- light.turn_on:
id: living_room_lights
transition_length: !lambda |-
int length = 1000;
if (x.containsKey("length"))
length = x["length"];
return length;
effect: !lambda |-
const char *effect = "None";
if (x.containsKey("effect"))
effect = x["effect"];
return effect;
i2c: i2c:
sda: 21 sda: 21
@ -599,6 +617,7 @@ light:
state = 0; state = 0;
- platform: rgb - platform: rgb
name: "Living Room Lights" name: "Living Room Lights"
id: living_room_lights
red: pca_0 red: pca_0
green: pca_1 green: pca_1
blue: pca_2 blue: pca_2

View file

@ -76,7 +76,14 @@ sensor:
- platform: mqtt_subscribe - platform: mqtt_subscribe
name: "MQTT Subscribe Sensor 1" name: "MQTT Subscribe Sensor 1"
topic: "mqtt/topic" topic: "mqtt/topic"
id: the_sensor
qos: 2 qos: 2
on_value:
- mqtt.publish_json:
topic: the/topic
payload: |-
root["key"] = id(the_sensor).value;
root["greeting"] = "Hello World";
- platform: cse7766 - platform: cse7766
voltage: voltage:
name: "CSE7766 Voltage" name: "CSE7766 Voltage"