diff --git a/esphomeyaml/components/binary_sensor/remote_receiver.py b/esphomeyaml/components/binary_sensor/remote_receiver.py index 61aeb634be..ad2f5cac31 100644 --- a/esphomeyaml/components/binary_sensor/remote_receiver.py +++ b/esphomeyaml/components/binary_sensor/remote_receiver.py @@ -10,8 +10,9 @@ from esphomeyaml.const import CONF_ADDRESS, CONF_CHANNEL, CONF_CODE, CONF_COMMAN CONF_DEVICE, CONF_FAMILY, CONF_GROUP, CONF_LG, CONF_NAME, CONF_NBITS, CONF_NEC, \ CONF_PANASONIC, CONF_PROTOCOL, CONF_RAW, CONF_RC_SWITCH_RAW, CONF_RC_SWITCH_TYPE_A, \ CONF_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C, CONF_RC_SWITCH_TYPE_D, CONF_SAMSUNG, CONF_SONY, \ - CONF_STATE -from esphomeyaml.cpp_generator import Pvariable, get_variable + CONF_STATE, CONF_ID +from esphomeyaml.cpp_generator import Pvariable, get_variable, progmem_array +from esphomeyaml.cpp_types import int32 DEPENDENCIES = ['remote_receiver'] @@ -35,6 +36,18 @@ RCSwitchTypeBReceiver = remote_ns.class_('RCSwitchTypeBReceiver', RCSwitchRawRec RCSwitchTypeCReceiver = remote_ns.class_('RCSwitchTypeCReceiver', RCSwitchRawReceiver) RCSwitchTypeDReceiver = remote_ns.class_('RCSwitchTypeDReceiver', RCSwitchRawReceiver) + +def validate_raw(value): + if isinstance(value, dict): + return vol.Schema({ + cv.GenerateID(): cv.declare_variable_id(int32), + vol.Required(CONF_DATA): [vol.Any(vol.Coerce(int), cv.time_period_microseconds)], + })(value) + return validate_raw({ + CONF_DATA: value + }) + + PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(RemoteReceiver), vol.Optional(CONF_LG): vol.Schema({ @@ -56,7 +69,7 @@ PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend vol.Required(CONF_ADDRESS): cv.hex_uint16_t, vol.Required(CONF_COMMAND): cv.hex_uint32_t, }), - vol.Optional(CONF_RAW): [vol.Any(vol.Coerce(int), cv.time_period_microseconds)], + vol.Optional(CONF_RAW): validate_raw, vol.Optional(CONF_RC_SWITCH_RAW): RC_SWITCH_RAW_SCHEMA, vol.Optional(CONF_RC_SWITCH_TYPE_A): RC_SWITCH_TYPE_A_SCHEMA, vol.Optional(CONF_RC_SWITCH_TYPE_B): RC_SWITCH_TYPE_B_SCHEMA, @@ -82,7 +95,8 @@ def receiver_base(full_config): if key == CONF_SONY: return SonyReceiver.new(name, config[CONF_DATA], config[CONF_NBITS]) if key == CONF_RAW: - return RawReceiver.new(name, *config) + arr = progmem_array(config[CONF_ID], config[CONF_DATA]) + return RawReceiver.new(name, arr, len(config[CONF_DATA])) if key == CONF_RC_SWITCH_RAW: return RCSwitchRawReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]), binary_code(config[CONF_CODE]), len(config[CONF_CODE])) diff --git a/esphomeyaml/components/font.py b/esphomeyaml/components/font.py index 290fe3a136..91e1076161 100644 --- a/esphomeyaml/components/font.py +++ b/esphomeyaml/components/font.py @@ -6,8 +6,8 @@ from esphomeyaml.components import display import esphomeyaml.config_validation as cv from esphomeyaml.const import CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_SIZE from esphomeyaml.core import CORE, HexInt -from esphomeyaml.cpp_generator import MockObj, Pvariable, RawExpression, add, safe_exp -from esphomeyaml.cpp_types import App +from esphomeyaml.cpp_generator import Pvariable, progmem_array, safe_exp +from esphomeyaml.cpp_types import App, uint8 from esphomeyaml.py_compat import sort_by_cmp DEPENDENCIES = ['display'] @@ -74,7 +74,7 @@ FONT_SCHEMA = vol.Schema({ vol.Required(CONF_FILE): validate_truetype_file, vol.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs, vol.Optional(CONF_SIZE, default=20): vol.All(cv.int_, vol.Range(min=1)), - cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(None), + cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(uint8), }) CONFIG_SCHEMA = vol.All(validate_pillow_installed, FONT_SCHEMA) @@ -108,14 +108,12 @@ def to_code(config): glyph_args[glyph] = (len(data), offset_x, offset_y, width, height) data += glyph_data - raw_data = MockObj(config[CONF_RAW_DATA_ID]) - add(RawExpression('static const uint8_t {}[{}] PROGMEM = {}'.format( - raw_data, len(data), - safe_exp([HexInt(x) for x in data])))) + rhs = safe_exp([HexInt(x) for x in data]) + prog_arr = progmem_array(config[CONF_RAW_DATA_ID], rhs) glyphs = [] for glyph in config[CONF_GLYPHS]: - glyphs.append(Glyph(glyph, raw_data, *glyph_args[glyph])) + glyphs.append(Glyph(glyph, prog_arr, *glyph_args[glyph])) rhs = App.make_font(glyphs, ascent, ascent + descent) Pvariable(config[CONF_ID], rhs) diff --git a/esphomeyaml/components/image.py b/esphomeyaml/components/image.py index ff0afe12bf..206f0dedca 100644 --- a/esphomeyaml/components/image.py +++ b/esphomeyaml/components/image.py @@ -8,8 +8,8 @@ from esphomeyaml.components import display, font import esphomeyaml.config_validation as cv from esphomeyaml.const import CONF_FILE, CONF_ID, CONF_RESIZE from esphomeyaml.core import CORE, HexInt -from esphomeyaml.cpp_generator import MockObj, Pvariable, RawExpression, add, safe_exp -from esphomeyaml.cpp_types import App +from esphomeyaml.cpp_generator import Pvariable, progmem_array, safe_exp +from esphomeyaml.cpp_types import App, uint8 _LOGGER = logging.getLogger(__name__) @@ -24,7 +24,7 @@ IMAGE_SCHEMA = vol.Schema({ vol.Required(CONF_ID): cv.declare_variable_id(Image_), vol.Required(CONF_FILE): cv.file_, vol.Optional(CONF_RESIZE): cv.dimensions, - cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(None), + cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(uint8), }) CONFIG_SCHEMA = vol.All(font.validate_pillow_installed, IMAGE_SCHEMA) @@ -56,10 +56,8 @@ def to_code(config): pos = x + y * width8 data[pos // 8] |= 0x80 >> (pos % 8) - raw_data = MockObj(config[CONF_RAW_DATA_ID]) - add(RawExpression('static const uint8_t {}[{}] PROGMEM = {}'.format( - raw_data, len(data), - safe_exp([HexInt(x) for x in data])))) + rhs = safe_exp([HexInt(x) for x in data]) + prog_arr = progmem_array(config[CONF_RAW_DATA_ID], rhs) - rhs = App.make_image(raw_data, width, height) + rhs = App.make_image(prog_arr, width, height) Pvariable(config[CONF_ID], rhs) diff --git a/esphomeyaml/components/switch/remote_transmitter.py b/esphomeyaml/components/switch/remote_transmitter.py index 065b351030..8c6e7e05ac 100644 --- a/esphomeyaml/components/switch/remote_transmitter.py +++ b/esphomeyaml/components/switch/remote_transmitter.py @@ -11,8 +11,9 @@ from esphomeyaml.const import CONF_ADDRESS, CONF_CARRIER_FREQUENCY, CONF_CHANNEL CONF_NAME, CONF_NBITS, CONF_NEC, CONF_PANASONIC, CONF_PROTOCOL, CONF_RAW, CONF_RC_SWITCH_RAW, \ CONF_RC_SWITCH_TYPE_A, CONF_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C, CONF_RC_SWITCH_TYPE_D, \ CONF_REPEAT, CONF_SAMSUNG, CONF_SONY, CONF_STATE, CONF_TIMES, \ - CONF_WAIT_TIME -from esphomeyaml.cpp_generator import Pvariable, add, get_variable + CONF_WAIT_TIME, CONF_ID +from esphomeyaml.cpp_generator import Pvariable, add, get_variable, progmem_array +from esphomeyaml.cpp_types import int32 DEPENDENCIES = ['remote_transmitter'] @@ -36,7 +37,18 @@ RCSwitchTypeBTransmitter = remote_ns.class_('RCSwitchTypeBTransmitter', RCSwitch RCSwitchTypeCTransmitter = remote_ns.class_('RCSwitchTypeCTransmitter', RCSwitchRawTransmitter) RCSwitchTypeDTransmitter = remote_ns.class_('RCSwitchTypeDTransmitter', RCSwitchRawTransmitter) -validate_raw_data = [vol.Any(vol.Coerce(int), cv.time_period_microseconds)] + +def validate_raw(value): + if isinstance(value, dict): + return vol.Schema({ + cv.GenerateID(): cv.declare_variable_id(int32), + vol.Required(CONF_DATA): [vol.Any(vol.Coerce(int), cv.time_period_microseconds)], + vol.Optional(CONF_CARRIER_FREQUENCY): vol.All(cv.frequency, vol.Coerce(int)), + })(value) + return validate_raw({ + CONF_DATA: value + }) + PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({ cv.GenerateID(): cv.declare_variable_id(RemoteTransmitter), @@ -59,10 +71,7 @@ PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({ vol.Required(CONF_ADDRESS): cv.hex_uint16_t, vol.Required(CONF_COMMAND): cv.hex_uint32_t, }), - vol.Optional(CONF_RAW): vol.Any(validate_raw_data, vol.Schema({ - vol.Required(CONF_DATA): validate_raw_data, - vol.Optional(CONF_CARRIER_FREQUENCY): vol.All(cv.frequency, vol.Coerce(int)), - })), + vol.Optional(CONF_RAW): validate_raw, vol.Optional(CONF_RC_SWITCH_RAW): RC_SWITCH_RAW_SCHEMA, vol.Optional(CONF_RC_SWITCH_TYPE_A): RC_SWITCH_TYPE_A_SCHEMA, vol.Optional(CONF_RC_SWITCH_TYPE_B): RC_SWITCH_TYPE_B_SCHEMA, @@ -94,14 +103,9 @@ def transmitter_base(full_config): if key == CONF_SONY: return SonyTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS]) if key == CONF_RAW: - if isinstance(config, dict): - data = config[CONF_DATA] - carrier_frequency = config.get(CONF_CARRIER_FREQUENCY) - else: - data = config - carrier_frequency = None - return RawTransmitter.new(name, data, - carrier_frequency) + arr = progmem_array(config[CONF_ID], config[CONF_DATA]) + return RawTransmitter.new(name, arr, len(config[CONF_DATA]), + config.get(CONF_CARRIER_FREQUENCY)) if key == CONF_RC_SWITCH_RAW: return RCSwitchRawTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]), binary_code(config[CONF_CODE]), len(config[CONF_CODE])) diff --git a/esphomeyaml/config_validation.py b/esphomeyaml/config_validation.py index 655be06465..48c352178a 100644 --- a/esphomeyaml/config_validation.py +++ b/esphomeyaml/config_validation.py @@ -46,6 +46,7 @@ RESERVED_IDS = [ 'App', 'pinMode', 'delay', 'delayMicroseconds', 'digitalRead', 'digitalWrite', 'INPUT', 'OUTPUT', + 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'int8_t', 'int16_t', 'int32_t', 'int64_t', ] diff --git a/esphomeyaml/core.py b/esphomeyaml/core.py index f8af920af8..cd81dc5241 100644 --- a/esphomeyaml/core.py +++ b/esphomeyaml/core.py @@ -261,10 +261,13 @@ class ID(object): self.type = type def resolve(self, registered_ids): + from esphomeyaml.config_validation import RESERVED_IDS + if self.id is None: base = str(self.type).replace('::', '_').lower() name = ''.join(c for c in base if c.isalnum() or c == '_') - self.id = ensure_unique_string(name, registered_ids) + used = set(registered_ids) | set(RESERVED_IDS) + self.id = ensure_unique_string(name, used) return self.id def __str__(self): diff --git a/esphomeyaml/cpp_generator.py b/esphomeyaml/cpp_generator.py index 37af8b82c4..fbfe991009 100644 --- a/esphomeyaml/cpp_generator.py +++ b/esphomeyaml/cpp_generator.py @@ -317,6 +317,27 @@ class ExpressionStatement(Statement): return u"{};".format(self.expression) +class ProgmemAssignmentExpression(AssignmentExpression): + def __init__(self, type, name, rhs, obj): + super(ProgmemAssignmentExpression, self).__init__( + type, '', name, rhs, obj + ) + + def __str__(self): + type_ = self.type + return u"static const {} {}[] PROGMEM = {}".format(type_, self.name, self.rhs) + + +def progmem_array(id, rhs): + rhs = safe_exp(rhs) + obj = MockObj(id, u'.') + assignment = ProgmemAssignmentExpression(id.type, id, rhs, obj) + CORE.add(assignment) + CORE.register_variable(id, obj) + obj.requires.append(assignment) + return obj + + def statement(expression): # type: (Union[Expression, Statement]) -> Statement if isinstance(expression, Statement): return expression