Store Raw Remote Codes in PROGMEM (#392)

* Store Raw Remote Codes in PROGMEM

* Lint

* Lint

* Fix
This commit is contained in:
Otto Winter 2019-02-10 16:41:12 +01:00 committed by GitHub
parent 8ce176aaba
commit 596f995af8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 36 deletions

View file

@ -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_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_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_RC_SWITCH_TYPE_B, CONF_RC_SWITCH_TYPE_C, CONF_RC_SWITCH_TYPE_D, CONF_SAMSUNG, CONF_SONY, \
CONF_STATE CONF_STATE, CONF_ID
from esphomeyaml.cpp_generator import Pvariable, get_variable from esphomeyaml.cpp_generator import Pvariable, get_variable, progmem_array
from esphomeyaml.cpp_types import int32
DEPENDENCIES = ['remote_receiver'] DEPENDENCIES = ['remote_receiver']
@ -35,6 +36,18 @@ RCSwitchTypeBReceiver = remote_ns.class_('RCSwitchTypeBReceiver', RCSwitchRawRec
RCSwitchTypeCReceiver = remote_ns.class_('RCSwitchTypeCReceiver', RCSwitchRawReceiver) RCSwitchTypeCReceiver = remote_ns.class_('RCSwitchTypeCReceiver', RCSwitchRawReceiver)
RCSwitchTypeDReceiver = remote_ns.class_('RCSwitchTypeDReceiver', 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({ PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(RemoteReceiver), cv.GenerateID(): cv.declare_variable_id(RemoteReceiver),
vol.Optional(CONF_LG): vol.Schema({ 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_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint32_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_RAW): RC_SWITCH_RAW_SCHEMA,
vol.Optional(CONF_RC_SWITCH_TYPE_A): RC_SWITCH_TYPE_A_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, 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: if key == CONF_SONY:
return SonyReceiver.new(name, config[CONF_DATA], config[CONF_NBITS]) return SonyReceiver.new(name, config[CONF_DATA], config[CONF_NBITS])
if key == CONF_RAW: 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: if key == CONF_RC_SWITCH_RAW:
return RCSwitchRawReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]), return RCSwitchRawReceiver.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
binary_code(config[CONF_CODE]), len(config[CONF_CODE])) binary_code(config[CONF_CODE]), len(config[CONF_CODE]))

View file

@ -6,8 +6,8 @@ from esphomeyaml.components import display
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_SIZE from esphomeyaml.const import CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_SIZE
from esphomeyaml.core import CORE, HexInt from esphomeyaml.core import CORE, HexInt
from esphomeyaml.cpp_generator import MockObj, Pvariable, RawExpression, add, safe_exp from esphomeyaml.cpp_generator import Pvariable, progmem_array, safe_exp
from esphomeyaml.cpp_types import App from esphomeyaml.cpp_types import App, uint8
from esphomeyaml.py_compat import sort_by_cmp from esphomeyaml.py_compat import sort_by_cmp
DEPENDENCIES = ['display'] DEPENDENCIES = ['display']
@ -74,7 +74,7 @@ FONT_SCHEMA = vol.Schema({
vol.Required(CONF_FILE): validate_truetype_file, vol.Required(CONF_FILE): validate_truetype_file,
vol.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs, vol.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs,
vol.Optional(CONF_SIZE, default=20): vol.All(cv.int_, vol.Range(min=1)), 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) 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) glyph_args[glyph] = (len(data), offset_x, offset_y, width, height)
data += glyph_data data += glyph_data
raw_data = MockObj(config[CONF_RAW_DATA_ID]) rhs = safe_exp([HexInt(x) for x in data])
add(RawExpression('static const uint8_t {}[{}] PROGMEM = {}'.format( prog_arr = progmem_array(config[CONF_RAW_DATA_ID], rhs)
raw_data, len(data),
safe_exp([HexInt(x) for x in data]))))
glyphs = [] glyphs = []
for glyph in config[CONF_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) rhs = App.make_font(glyphs, ascent, ascent + descent)
Pvariable(config[CONF_ID], rhs) Pvariable(config[CONF_ID], rhs)

View file

@ -8,8 +8,8 @@ from esphomeyaml.components import display, font
import esphomeyaml.config_validation as cv import esphomeyaml.config_validation as cv
from esphomeyaml.const import CONF_FILE, CONF_ID, CONF_RESIZE from esphomeyaml.const import CONF_FILE, CONF_ID, CONF_RESIZE
from esphomeyaml.core import CORE, HexInt from esphomeyaml.core import CORE, HexInt
from esphomeyaml.cpp_generator import MockObj, Pvariable, RawExpression, add, safe_exp from esphomeyaml.cpp_generator import Pvariable, progmem_array, safe_exp
from esphomeyaml.cpp_types import App from esphomeyaml.cpp_types import App, uint8
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -24,7 +24,7 @@ IMAGE_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(Image_), vol.Required(CONF_ID): cv.declare_variable_id(Image_),
vol.Required(CONF_FILE): cv.file_, vol.Required(CONF_FILE): cv.file_,
vol.Optional(CONF_RESIZE): cv.dimensions, 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) CONFIG_SCHEMA = vol.All(font.validate_pillow_installed, IMAGE_SCHEMA)
@ -56,10 +56,8 @@ def to_code(config):
pos = x + y * width8 pos = x + y * width8
data[pos // 8] |= 0x80 >> (pos % 8) data[pos // 8] |= 0x80 >> (pos % 8)
raw_data = MockObj(config[CONF_RAW_DATA_ID]) rhs = safe_exp([HexInt(x) for x in data])
add(RawExpression('static const uint8_t {}[{}] PROGMEM = {}'.format( prog_arr = progmem_array(config[CONF_RAW_DATA_ID], rhs)
raw_data, len(data),
safe_exp([HexInt(x) for x in data]))))
rhs = App.make_image(raw_data, width, height) rhs = App.make_image(prog_arr, width, height)
Pvariable(config[CONF_ID], rhs) Pvariable(config[CONF_ID], rhs)

View file

@ -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_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_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_REPEAT, CONF_SAMSUNG, CONF_SONY, CONF_STATE, CONF_TIMES, \
CONF_WAIT_TIME CONF_WAIT_TIME, CONF_ID
from esphomeyaml.cpp_generator import Pvariable, add, get_variable from esphomeyaml.cpp_generator import Pvariable, add, get_variable, progmem_array
from esphomeyaml.cpp_types import int32
DEPENDENCIES = ['remote_transmitter'] DEPENDENCIES = ['remote_transmitter']
@ -36,7 +37,18 @@ RCSwitchTypeBTransmitter = remote_ns.class_('RCSwitchTypeBTransmitter', RCSwitch
RCSwitchTypeCTransmitter = remote_ns.class_('RCSwitchTypeCTransmitter', RCSwitchRawTransmitter) RCSwitchTypeCTransmitter = remote_ns.class_('RCSwitchTypeCTransmitter', RCSwitchRawTransmitter)
RCSwitchTypeDTransmitter = remote_ns.class_('RCSwitchTypeDTransmitter', 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({ PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(RemoteTransmitter), 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_ADDRESS): cv.hex_uint16_t,
vol.Required(CONF_COMMAND): cv.hex_uint32_t, vol.Required(CONF_COMMAND): cv.hex_uint32_t,
}), }),
vol.Optional(CONF_RAW): vol.Any(validate_raw_data, vol.Schema({ vol.Optional(CONF_RAW): validate_raw,
vol.Required(CONF_DATA): validate_raw_data,
vol.Optional(CONF_CARRIER_FREQUENCY): vol.All(cv.frequency, vol.Coerce(int)),
})),
vol.Optional(CONF_RC_SWITCH_RAW): RC_SWITCH_RAW_SCHEMA, 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_A): RC_SWITCH_TYPE_A_SCHEMA,
vol.Optional(CONF_RC_SWITCH_TYPE_B): RC_SWITCH_TYPE_B_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: if key == CONF_SONY:
return SonyTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS]) return SonyTransmitter.new(name, config[CONF_DATA], config[CONF_NBITS])
if key == CONF_RAW: if key == CONF_RAW:
if isinstance(config, dict): arr = progmem_array(config[CONF_ID], config[CONF_DATA])
data = config[CONF_DATA] return RawTransmitter.new(name, arr, len(config[CONF_DATA]),
carrier_frequency = config.get(CONF_CARRIER_FREQUENCY) config.get(CONF_CARRIER_FREQUENCY))
else:
data = config
carrier_frequency = None
return RawTransmitter.new(name, data,
carrier_frequency)
if key == CONF_RC_SWITCH_RAW: if key == CONF_RC_SWITCH_RAW:
return RCSwitchRawTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]), return RCSwitchRawTransmitter.new(name, build_rc_switch_protocol(config[CONF_PROTOCOL]),
binary_code(config[CONF_CODE]), len(config[CONF_CODE])) binary_code(config[CONF_CODE]), len(config[CONF_CODE]))

View file

@ -46,6 +46,7 @@ RESERVED_IDS = [
'App', 'pinMode', 'delay', 'delayMicroseconds', 'digitalRead', 'digitalWrite', 'INPUT', 'App', 'pinMode', 'delay', 'delayMicroseconds', 'digitalRead', 'digitalWrite', 'INPUT',
'OUTPUT', 'OUTPUT',
'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t', 'int8_t', 'int16_t', 'int32_t', 'int64_t',
] ]

View file

@ -261,10 +261,13 @@ class ID(object):
self.type = type self.type = type
def resolve(self, registered_ids): def resolve(self, registered_ids):
from esphomeyaml.config_validation import RESERVED_IDS
if self.id is None: if self.id is None:
base = str(self.type).replace('::', '_').lower() base = str(self.type).replace('::', '_').lower()
name = ''.join(c for c in base if c.isalnum() or c == '_') 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 return self.id
def __str__(self): def __str__(self):

View file

@ -317,6 +317,27 @@ class ExpressionStatement(Statement):
return u"{};".format(self.expression) 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 def statement(expression): # type: (Union[Expression, Statement]) -> Statement
if isinstance(expression, Statement): if isinstance(expression, Statement):
return expression return expression